Sunday, September 26, 2010

Silverlight client for REST using MVVM

In my previous post I talked about MVVM model. Here I will demonstrate a very simple implementation of MVVM model to create a Silverlight client for consuming REST Service.

The application is a netflix catalog using MVVM model and it is based on this sample.

The Application has 3 project

1. Silverlight UI containing the View and the ViewModel.
2. Silverlight dll project containing the Business Model or the Model.
3. Web project containing the page to host the Silverlight application.

I'll start from implementing the Model.

1st of all we need to know our DataModel, which in our case would be created by adding a service reference to the http://odata.netflix.com/catalog

If you are using Visual Studio 2010, you may create a new Silverlight library project called Model and Add a Service reference pointing to http://odata.netflix.com/catalog


On successful creation of ServiceRefrence, the service.edmx file will be generated along with the Reference. these files will be hidden by default. You've to click on "Show All Files" to view them. This will be our DataModel

After adding the ServiceRefrence successfully, we may proceed to add the Business Model or Model and name it CatalogModel.

CatalogModel will have to implement the INotificationChanged interface to notify any change in property.

public class CatalogModel:INotifyPropertyChanged

        #region INotify implementation
        public event PropertyChangedEventHandler PropertyChanged;

        private void raisePropertryChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion
        private Visibility _isLoadingGenres = Visibility.Visible;
        public Visibility IsLoadingGenres
        {
            get { return _isLoadingGenres; }
            set
            {
                _isLoadingGenres = value;
                raisePropertryChanged("IsLoadingGenres");
            }
        }

        private Visibility _isLoadingTitles;
        public Visibility IsLoadingTitles
        {
            get { return _isLoadingTitles; }
            set
            {
                _isLoadingTitles = value;
                raisePropertryChanged("IsLoadingTitles");
            }
        }
public DataServiceCollection<Genre> Genres { get; set; }
        private Genre _selectedGenre;
        public Genre SelectedGenre
        {
            get
            {
                return _selectedGenre;
            }
            set
            {
                if (value != _selectedGenre)
                {
                    _selectedGenre = value;
                    _selectedGenre.Titles.LoadCompleted += (s, e) =>
                        {
                            IsLoadingTitles = Visibility.Collapsed;
                        };
                    _selectedGenre.Titles.LoadAsync();
                    IsLoadingTitles = Visibility.Visible;
                    raisePropertryChanged("SelectedGenre");
                }
            }
        }
        public CatalogModel()
        {
            NetflixCatalog _context = new NetflixCatalog(new Uri("http://odata.netflix.com/Catalog/"));
            Genres = new DataServiceCollection<Genre>();
            var query = (from g in _context.Genres
                         orderby
                             g.Name
                         select g);
            Genres.LoadCompleted += (s, e) =>
                {
                    IsLoadingGenres = Visibility.Collapsed;
                };
            Genres.LoadAsync(query);
            IsLoadingGenres = Visibility.Visible;
        }
 }

Now we will create our ViewModel. Go to your Silverlight UI project and add a new class called ViewModel;
public class ViewModel:INotifyPropertyChanged
    {
        private CatalogModel _model = new CatalogModel();
        public CatalogModel Model
        {
            get
            {
                return _model;
            }
            set
            {
                _model = value;
                raisePropertryChanged("Model");
            }
        }

        #region INotify implementation
        public event PropertyChangedEventHandler PropertyChanged;

        private void raisePropertryChanged(string propertyName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }
        #endregion

Now we will construct the View, that is the XAML:

<Grid x:Name="LayoutRoot" Background="White" Width="360" Margin="20">
        <Grid.Resources>
            <local:ViewModel x:Name="MainPageViewModel"/>
        </Grid.Resources>
        <StackPanel DataContext="{StaticResource MainPageViewModel}" >
            <StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
                <TextBlock Text="Select Genere" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="0,0,5,0"  />
                <ComboBox Name="GenreCombobox" ItemsSource="{Binding Model.Genres}" SelectedItem="{Binding Model.SelectedGenre, Mode=TwoWay}"  DisplayMemberPath="Name" VerticalAlignment="Center" HorizontalAlignment="Left" MinWidth="150" />
                <TextBlock Text="Loading..."  Visibility="{Binding Model.IsLoadingGenres}" Margin="-140,0,0,0"/>
            </StackPanel>
            <ListBox Name="CatalogTitleListBox" DataContext="{Binding Model.SelectedGenre}" ItemsSource="{Binding Titles}" Margin="0,5" Height="535" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{Binding BoxArt.MediumUrl}"  />
                            <StackPanel Orientation="Vertical">
                                <TextBlock Text="{Binding Name}" FontSize="14" FontFamily="Lucida Sans Unicode" FontWeight="Bold"></TextBlock>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock>Rated:</TextBlock>
                                    <TextBlock Text="{Binding Rating}" FontSize="12" FontFamily="Lucida Sans Unicode"></TextBlock>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock>Release Year:</TextBlock>
                                    <TextBlock Text="{Binding ReleaseYear}" FontSize="12" FontFamily="Lucida Sans Unicode"></TextBlock>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock>Average User Rating:</TextBlock>
                                    <TextBlock Text="{Binding AverageRating}"></TextBlock>
                                    <TextBlock> /5</TextBlock>
                                </StackPanel>
                                <StackPanel Orientation="Horizontal">
                                    <TextBlock>I've seen it</TextBlock>
                                    <CheckBox IsChecked="{Binding Seen}"/>
                                </StackPanel>
                            </StackPanel>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </StackPanel>
    </Grid>

There is 0 lines of code in the code behind file of xaml.cs

This was a very simple implementation of MVVM model.

Tuesday, September 14, 2010

MVVM Model with WCF Async

You might have heard alot about the MVVM model being implemented in WPF and Silverlight and you must be knowing that the paradigm MVVM stands for M(Model)-V(View)-VM-(ViewModel).

Althought as per the actual implementation of this model, following the flow of data/commands it should have been called as View-ViewModel-Model following the command path (meaning the command is invoked by the view which in return calls the ViewModel and the ViewModel invokes the Model). Or it should have been called as Model-ViewMode-View following the data path (Meaning the Model passes the data to ViewMode and the ViewModel passes it to View.

Any ways there are many things in life that are wrongly named so is our dear MVVM model.

I read a couple of articles on MVVM patter but no one gave me details on how to implement it with Asnyc calls executed to get data from WCF service/s. Meaning it seemed incomplete because most of the Silverlight apps consumes a WCF service/s. Any ways, my purpose of writing this blog is to help the developers understand how to implement MVVM and demonstrate the flexibility it provides.

Please note that the advantages and flexibility of MVVM is not only limited to the behavior that I explain in this blog.

Okay, so lets start by answering some basic questions.

What actually this Model-View-ViewModel refers to?
I would prefer to take the Command path to explain it better because it starts with a visualization.

View - refers to the UI. It can be a page or a user control. If you are creating a WPF or Silverlight application then View will refer to the page/user control that contains the XAML to create the User Interface. The entire application may contain a single view or it may contain multiple views. Meaning, if you are creating a Multiple paged application for example a Navigation Application in silverlight then each page that you contain should be considered as a View.

Flexibility: You may have a single view that all your pages/user control can refer to. Or you can have multiple views one for each page or user control.

ViewMode: View is going to invoke the ViewModel. It means that the User Interface or View or Page or UserControl (whatever you may call it) is going to initiate the request for data from the ViewModel. The request for data can be made either thought an event or a command. For example, you can create a new instance/object of ViewModel on a ButtonClick event or Loaded event or any other event. Or you can use Command

Flexibility: View model is basically a user interface representation of the business model with additional properties to interact with the View. For example, the data service failed to get the data in time specified and you get a time out error. In this case, you may not want the user to know about this and can make a call again. Or you may want the user to know about this and still make a call again or better you inform the user and let him choose to make a call again or not. This decision can be taken in the ViewModel by adding a property and binding it to the control. Another example can be showing the progress bar while the async method completes. You can add a property in the ViewMode called ShowProgressBar and bind it to the progressbar control's visibility.

Please note that your ViewModel should implement the INotificationPropertyChanged to let the view know if any property changes.
Model: refers to the Business Model. The model is invoked by the ViewModel. The model in return makes a call to get the data.

Flexibility: The data service may return the data model. In Model you can construct your business model by adding extra properties to the data model or by combining multiple data models.

Please note that your Model should also implement the INotificationPropertyChanged to let the ViewModel know when any property changes.

Below images will help you better understand.



 













I will continue this post with the code snippet as well as a sample application soon.