Skip to content

MVVM programming with Caliburn Micro

BorjaFG edited this page Mar 17, 2019 · 5 revisions

Naming conventions

Caliburn Micro uses conventions to help finding the right view for a view-model: the view is appended "View" and the view-model is appended "View-model". So, for example, the class App would have a view-model called AppViewModel, and its view would be named AppView.

In general, we have only used ViewModels and Views, not Models. We use ViewModels to store all the variables and the logic used in a class. The View handles how to display the information in the ViewModel and consists of a XAML file. The View contains bindings (references) to the ViewModel.

ViewModels inherit from PropertyChangedBase when they are to be used within a window, or, if they are going to be used as a window, from Screen.

Example: HerdAgent

This class encapsulates the information of a remote Herd agent: its IP address, its status, ....

This information is stored in the ViewModel (HerdAgentViewModel):

    public class HerdAgentViewModel : PropertyChangedBase
    {
      private HerdAgentInfo m_herdAgentInfo;
      public HerdAgentViewModel(HerdAgentInfo info)
      {
        m_herdAgentInfo = info;
      }
      public IPEndPoint ipAddress
      {
        get { return m_herdAgentInfo.ipAddress; }
        set { m_herdAgentInfo.ipAddress = value; } 
      }
      public string ipAddressString { get { return m_herdAgentInfo.ipAddressString; } set { } }
      public DateTime lastACK { get { return m_herdAgentInfo.lastACK; }
      set { m_herdAgentInfo.lastACK = value; } }
      public int numProcessors { get { return m_herdAgentInfo.numProcessors; } }
      public bool isAvailable { get { return m_herdAgentInfo.isAvailable; } }
      public string version { get { return m_herdAgentInfo.version; } }
      public string status
      {
        get { return m_herdAgentInfo.state; }
        set { m_herdAgentInfo.state = value; NotifyOfPropertyChange(() => status); }
      }
    }

Notice that we use another convention to distinguish private variables (m_ prefix) from the property (no prefix) which exposes the value.

The View is named HerdAgentView and contains the following:

    <UserControl x:Class="Badger.Views.HerdAgentView" ...>
      <UserControl.Resources>
        <BooleanToVisibilityConverter x:Key="BoolToVis" />
      </UserControl.Resources>
      <Border Margin="0" BorderThickness="1">
          <StackPanel Orientation="Vertical" Width="230">
            <StackPanel Orientation="Horizontal" Height="20" VerticalAlignment="Top" HorizontalAlignment="Center">
              <TextBlock IsEnabled="False" x:Name="ipAddressString" Width="80" FontSize="10" Margin="0,0,5,0" />
              <TextBlock IsEnabled="False" x:Name="version" Foreground="Black" FontSize="8" Margin="0,0,5,0" Width="30"/>
              <TextBlock IsEnabled="False" x:Name="status" Foreground="Black" FontSize="8" Margin="0,0,5,0" Width="30"/>
              <TextBlock IsEnabled="False" x:Name="numProcessors" Foreground="Black" FontSize="8" Margin="0,0,5,0" Width="10"/>
            </StackPanel>
          </StackPanel>
      </Border>
    </UserControl>

Notice the bindings in bold letters. Most of the time, we simply bind a property to the view by setting some objects name: x:Name="propertyName".

Another example: Shepherd

When we want to use a set of objects as the source of a visual object (ItemsControl, ComboBox, TreeView, ...), we store them as a list (BindableCollection from Caliburn.Micro is recommended) and then bind them to the view.

For example, the class Shepherd stores a list of HerdAgents:

    public class ShepherdViewModel : PropertyChangedBase
    {
      private BindableCollection <HerdAgentViewModel> m_herdAgentList= new BindableCollection<HerdAgentViewModel>();
      public BindableCollection<HerdAgentViewModel> herdAgentList
      {
        get{return m_herdAgentList;}
      } //no set means it's read-only
    }

And we bind this list to the view by the name:

    <ItemsControl x:Name="herdAgentList"/>
Clone this wiki locally