Click or drag to resize
Binding to ViewModel Data

Before the ViewModel data can be accessed by the View, an object of the former needs to be set as the DataContext of the latter. Here, this is done in the code-behind of the View:

C#
public MainWindow()
{
    this.InitializeComponent();
    this.DataContext = new MainWindowViewModel(Properties.Settings.Default);
    this.ViewModel.ScrollEventIntoView += this.OnScrollEventIntoView;
    this.ViewModel.ListenFailed += this.OnListenFailed;
}

Note that an object of the Settings class (which acts as the Model here) is passed to the MainWindowViewModel constructor.

This topic contains the following sections:

Primitive Properties
XAML
<TextBox
    Grid.Row="2" Grid.Column="2" Grid.ColumnSpan="2" IsEnabled="{Binding CanEditSettings}"
    ToolTip="The host name or IP address of the Ember+ provider." Text="{Binding ProviderHostName}"/>

The Text="{Binding ProviderHostName}" part in the code above establishes a two-way binding between MainWindowViewModel.ProviderHostName and TextBox.Text. This means that the following operations take place automatically:

Composite Properties
XAML
<local:ConnectionStatusUserControl
    Grid.Row="0" Grid.Column="0" DataContext="{Binding ConsumerConnection}"
    Header="Consumer to Proxy Connection Status"/>
<local:ConnectionStatusUserControl
    Grid.Row="0" Grid.Column="2" DataContext="{Binding ProviderConnection}"
    Header="Proxy to Provider Connection Status"/>

The DataContext="{Binding ConsumerConnection}" and DataContext="{Binding ProviderConnection}" parts in the code above bind the ConnectionViewModel values returned by the properties to the DataContext of the two ConnectionStatusUserControl instances. This allows ConnectionStatusUserControl to bind directly to ConnectionViewModel properties:

XAML
<Label Grid.Row="0" Grid.Column="0">Connection Attempts:</Label>
<TextBox
    Grid.Row="0" Grid.Column="2" IsReadOnly="True"
    ToolTip="The number of connection attempts made since the proxy was started."
    Text="{Binding ConnectionCount, Mode=OneWay}"/>
<Label Grid.Row="2" Grid.Column="0">Bytes Received:</Label>
<TextBox
    Grid.Row="2" Grid.Column="2" IsReadOnly="True"
    ToolTip="The number of bytes the proxy has received through the current connection."
    Text="{Binding BytesReceived, Mode=OneWay}"/>
<Label Grid.Row="4" Grid.Column="0">Seconds Since Last Byte:</Label>
<TextBox
    Grid.Row="4" Grid.Column="2" IsReadOnly="True"
    ToolTip="The number of seconds that have passed since the proxy has received the last byte."
    Text="{Binding SecondsSinceLastReceived, Mode=OneWay}"/>

Note how we have used ConnectionStatusUserControl in MainWindow and ConnectionViewModel in MainWindowViewModel to avoid duplicating identical parts.

Collection Properties
XAML
<DataGrid
    Margin="{StaticResource Margin}" SelectionMode="Single" CanUserResizeRows="False"
    CanUserResizeColumns="False" CanUserReorderColumns="False" CanUserSortColumns="False"
    ToolTip="Lists events in chronological order." ItemsSource="{Binding Events}"
    SelectedItem="{Binding SelectedEvent}" AutoGeneratingColumn="OnDataGrid_AutoGeneratingColumn"
    x:Name="EventsDataGrid"/>

The ItemsSource="{Binding Events}" part ensures that the elements in the ReadOnlyObservableCollectionT are shown in the DataGrid. Since the collection implements INotifyCollectionChanged, any changes to the collection are immediately reflected in the GUI. The SelectedItem="{Binding SelectedEvent}" part makes the currently selected Event available in the MainWindowViewModel.