MSDN Magazine - March 2009 - (Page 62) The GameCatalog class simply wraps the ADO.NET Data Service so that when a request for data comes in (GetGames or GetGamesByGenre), it executes the request and throws an event that contains the data (or an error, if one occurs). This code is meant to simplify access to the data without imparting any specific knowledge to the caller. The class includes an overloaded constructor to specify the URI of the service, but that is not always needed and could be implemented as a configuration element instead. Figure 3 shows the code for the GameCatalog class. Notice the ExecuteGameQuery method, which takes the ADO.NET Data Service query and executes it. This method executes the result asynchronously and returns the result to the caller. Note that the model executes the query but simply fires events when it is complete. You might look at this and wonder why the model doesn’t ensure that the events marshal the calls to the user interface thread in Silverlight . The reason is that Silverlight (like its other user interface brethren, such as Windows Forms and WPF) can only update the user interface from a main or UI thread. But if we do that marshaling in this code, it would tie our model to the user interface, which is exactly counter to our stated purpose (separating the concerns). If you assume that the data needs to be returned on the UI thread, you bind this class to user interface calls, but this is antithetical to why you use separate layers in an application. Views and the View Model It might seem obvious to create the view model to expose data directly to our view class(es). The problem with this approach is that the view model should only expose data that is directly needed by the view; therefore, you need to understand what the view needs. In many cases, you will be creating the view model and the view in parallel, refactoring the view model when the view has new requirements. Although the view model is exposing data to the view, the view is also interacting with the entity classes (indirectly because the model’s entities are being passed to the view by the view model). In this example, we have a simple design that is used to browse XBox game data, as shown in Figure 4. This design implies that we need a list of Game entities from our model filtered by genre (selected via the drop-down list). To fulfill this requirement, the example needs a view model that exposes the following: • A data-bindable Game list for the currently selected genre. • A method to make the request for the genre selected. • An event that alerts the UI that the list of games has been updated (because our data requests will be asynchronous). Once our view model supports this set of requirements, it can be bound to the XAML directly, as shown in GameView.XAML (located in the MVVM.Client project). This binding is implemented by creating a new instance of the view model in the Resources of the view and then binding the main container (a Grid in this case) to the view model. This implies that the entire XAML file will be data bound based on the view model directly. Figure 5 shows the GameView.XAML code. Our view model needs to fulfill these requirements using an IGameCatalog interface. In general, its useful to have the default constructor of a view model create a default model so that binding to the XAML is easy, but you should also include an overload of the constructor in which the model is supplied to allow for scenarios such as testing. The example view model (GameViewModel) looks like Figure 6. Of particular interest in the view model are the handlers for GameLoadingComplete (and GameLoadingError). These handlers receive events from the model and then fire events to the view. What is interesting here is that the model passes the view model the list of results, but instead of passing the results directly to the underlying view, the view model stores the results in their own bindable list (ObservableCollection ). This behavior occurs because the view model is being bound directly to the view, so the results will show up in the view via the data binding. Because the view model has knowledge of the user interface (because its purpose is to fulfill UI requests), it can then make sure that the events that it fires happen on the UI thread (via Dispatcher.BeginInvoke, although you can use other methods for Silverlight MVVM Figure 4 Example User Interface Figure 5 GameView.XAML // GameView.XAML 62 msdn magazine
For optimal viewing of this digital publication, please enable JavaScript and then refresh the page. If you would like to try to load the digital publication without using Flash Player detection, please click here.