This is an old revision of the document!
Implementing MVVM
Setup the following:
- Model: Data models or data structures implemented as classes.
- ViewModel: Models of the data as “viewed” or required by the Views. A ViewModel encapsulates a Model and exposes it in a format that the View can use.
- View: Data binding to ViewModel, with little “code-behind” to implement. It displays a limited window into the Model (data).
Main View
The Main View
should implement an instance of ViewModel as a ObjectDataProvider (in XAML), that we call AppViewModel
.
<UserControl x:Class="Acme.App.ucMainView" ... xmlns:viewmodel="Acme.App.ViewModel"> <UserControl.Resources> <!-- Instantiate the main AppViewModel object --> <viewmodel:TAppViewModel x:Key="AppViewModelDataSource" /> </<UserControl.Resources> ... </UserControl>
Alternatively, it can be spelled out as:
<UserControl.Resources> <!-- Instantiate the main AppViewModel object --> <ObjectDataProvider x:Key="AppViewModelDataSource" ObjectType="{x:Type viewmodel:TAppViewModel }" /> </<UserControl.Resources>
User Controls
User Controls in Main View
should implement an AppViewModel
dependency property. For example, user controls should be called as:
<TabControl> <TabItem> <Grid> <ucUserControlTriangle ViewModel="{Binding AppViewModelDataSource}"/> </Grid> </TabItem> <TabItem> <Grid> <ucUserControlSquare ViewModel="{Binding AppViewModelDataSource}"/> </Grid> </TabItem> <TabItem> <Grid> <ucUserControlCircle ViewModel="{Binding AppViewModelDataSource}"/> </Grid> </TabItem> </TabControl>
The dependency property AppViewModel
would be implemented like this:
public class ucUserControlTriangle : UserControl { ///------------------------------- /// Dependency Properties ///------------------------------- // Dependency Property public static readonly DependencyProperty AppViewModelProperty = DependencyProperty.Register( "AppViewModel", typeof(TAppViewModel), typeof(ucUserControlTriangle), new FrameworkPropertyMetadata(new TAppViewModel(), OnAppViewModelPropertyChanged, OnCoerceAppViewModelProperty ), OnValidateAppViewModelProperty ); // .NET Property Wrapper public TAppViewModel AppViewModel { // Important: Do not add any logic to these properties, because they are only // called when you set the property from code. If you set the property from XAML // the SetValue() method is called directly. get { return (TAppViewModel)GetValue(AppViewModelProperty); } set { SetValue(AppViewModelProperty, value); } } ///------------------------------- /// Constructor ///------------------------------- public ucUserControlTriangle() { InitializeComponents(); // Set DataContext this.DataContext = AppViewModel; } ///---------------------------------------------------------------------------------------- /// <summary> /// /// </summary> /// <param name="source"></param> /// <param name="e"></param> ///---------------------------------------------------------------------------------------- private static void OnAppViewModelPropertyChanged( DependencyObject source, DependencyPropertyChangedEventArgs e) { ucWorkshopRegistration control = source as ucWorkshopRegistration; //DateTime time = (DateTime)e.NewValue; // Put some update logic here... control.DataContext = (TAppViewModel)e.NewValue; } ///---------------------------------------------------------------------------------------- /// <summary> /// /// </summary> /// <param name="sender"></param> /// <param name="data"></param> /// <returns></returns> ///---------------------------------------------------------------------------------------- private static object OnCoerceAppViewModelProperty(DependencyObject sender, object data) { //if ((DateTime)data > DateTime.Now) //{ // data = DateTime.Now; //} return data; } ///---------------------------------------------------------------------------------------- /// <summary> /// /// </summary> /// <param name="data"></param> /// <returns></returns> ///---------------------------------------------------------------------------------------- private static bool OnValidateAppViewModelProperty(object data) { return data is TAppViewModel; } ... }
Set that user control's DataContext
property to AppViewModel
dependency property.
///------------------------------- /// Constructor ///------------------------------- public ucUserControlTriangle() { InitializeComponents(); // Set DataContext to dependency property AppViewModel this.DataContext = AppViewModel; }
Add Data Binding to controls inside that user control, taking advantage of DataContext
set to the AppViewModel
. For example, a DataGrid
would look like this:
<UserControl x:Class="Acme.App.ucUserControlTriangle" ... xmlns:viewmodel="Acme.App.ViewModel"> ... <!-- <DataGrid ItemsSource="{Binding Path=TSubCategoryHere}" Margin="5" AutoGenerateColumns="False"> --> <DataGrid ItemsSource="{Binding}" Margin="5" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Binding="{Binding Path=Type}" Header="Type" /> <DataGridTextColumn Binding="{Binding Path=Name}" Header="Name" /> <DataGridTextColumn Binding="{Binding Path=Color}" Header="Color" /> </DataGrid.Columns> </DataGrid> </UserControl>