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:
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:
<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:
Initialization: When the DataContext is set, MainWindow automatically calls the MainWindowViewModel.ProviderHostName getter and assigns the value to TextBox.Text. MainWindow also automatically subscribes to NotifyPropertyChangedPropertyChanged.
Change Propagation from View to ViewModel: When the user changes the text in the TextBox, MainWindow automatically sets the new value on MainWindowViewModel.ProviderHostName.
Change Propagation from ViewModel to View: When the business logic changes MainWindowViewModel.ProviderHostName, the NotifyPropertyChangedPropertyChanged event is raised. Since MainWindow is subscribed to the event it then automatically calls the MainWindowViewModel.ProviderHostName property getter and sets the value on TextBox.Text.
<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:
<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.
<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.