Recall that the only files in the project folder itself are App.xaml and its code-behind file App.xaml.cs. These files are responsible for “kicking off” the application. Let’s begin by looking at App.xaml:
The critical element here is the Startup attribute of the Application tag. Its value says, “Invoke the code found in the OnStartup event handler." This event handler is found in the code-behind file App.xaml.cs:
Here, a main window for the application is created (MainView), the data source for its controls is established (MainViewModel), and the window is displayed. Where did MainView and MainViewModel come from? Referring again to Figure 1, notice that the WPF-MVVM template provides initial versions of these classes for you in the Views and the ViewModels folders, respectively.
Looking at the XAML for MainView, we find an initial File menu with an Exit menu item that is linked to ‘ExitCommand’, and an empty grid:
However, there is no code-behind except for a constructor that invokes an InitializeComponent method to paint the window controls on your display:
Where is ExitCommand defined? Recall that the OnStartup event handler in App.xaml.cs established MainViewModel as the primary data source (i.e., DataContext) for MainView. Here we find the mysterious ExitCommand:
Notice that it is a read-only property of type ICommand. The ICommand interface, which must be implemented in all commands that interact with WPF, exposes two methods and an event. The first method, Execute, defines the method that is called when the command is invoked. The signature for this method must agree with that of the Action delegate:
public delegate void Action() or
public delegate void Action( T parameter )
public delegate void Action
The second method, CanExecute, defines the method that determines whether or not the command can execute in its current state. Its signature must agree with that of the Predicate delegate:
public delegate bool Predicate() or
public delegate bool Predicate( T parameter )
public delegate bool Predicate
The event, CanExecuteChanged, occurs when changes that affect whether or not the command should execute occur. The WPF-MVVM template provides a DelegateCommand class, located in the Commands folder, that implements this interface. In most situations you will be able to use this class “as is” to define additional commands in MainViewModel or in any other view model class you may need to create.
The other class in the Commands folder, CommandReference, provides a Command dependency property, so you can more easily bind a keyboard sequence – e.g., Control + X – to a command. A discussion of dependency properties is beyond the scope of this blog entry. Just bear in mind that all bindable control properties are dependency properties.
You will no doubt note that in MainViewModel, only the Execute method – aptly named Exit – is defined. MainViewModel relies on the default implementation of CanExecute provided by DelegateCommand, which merely returns ‘true’. Neither does it subscribe to the CanExecuteChanged event, for which, again DelegateCommand provides a default handler implementation.
The other mystery found in the MainViewModel class definition is the fact that it is a sub-class of ViewModelBase. This base class implements the INotifyPropertyChanged interface, which consists of a single event – PropertyChanged. It also provides a handler for that event:
WPF relies on the INotifyPropertyChanged event to establish proper communication between a view’s control properties and the data source for those properties. Implementing this interface in the data source class enables WPF to update the control property when its defined data source property changes, and vice versa. Since most view model classes are involved in this process, having ViewModelBase as a base class facilitates this effort.
That’s about it for an overview of the application project generated by the WPF-MVVM template. However, as you may recall, this template also gives you the option of generating a test project to go along with the application. If you refer back to Figure 1, you will notice that a single test class, MainViewModelTest, is generated. Within that class a single test method is generated. This method provides a stub for testing the MainViewModel constructor.
One of the primary advantages of adopting the MVVM pattern when developing a WPF application is that it enables you to test all of your code, including command execution, in a manner that is independent of the application UI. If you adopt this template, I would suggest that you define folders in the test project that correspond to the folders in the application project, and that you create one test class per application class.
With this overview behind us, we will proceed with the development of the Investment Tracker application in the next post.
Previous posts in this series:








No comments:
Post a Comment