Showing posts with label MVVM. Show all posts
Showing posts with label MVVM. Show all posts

Tuesday, April 8, 2014

Reactive UI - Part I [ Setting the Ground Up ]

All of us who have been designing and developing using XAML technologies use ICommand interface on a daily basis. The interface requires implementation of Execute() and CanExecute() methods. Here Execute method is used to perform an action in response to a user interaction. However, the action can only be executed if CanExecute() method returns true. You might have commonly seen a Command being bound to a button. In this case, button would be enabled or disabled based on the evaluation of CanExecute() method of the ICommand. Now let me throw the main question in the air...

Can we run into a situation when a button is enabled when it is not supposed to, and How often ICommand.CanExecute() is called?

Let me first give you the answer of first part of the question, YES, we can certainly run into situations when a button should be disabled when it is supposed to be enabled and vice versa.

The second part of the question is tricky. It is dependent upon the implementation of ICommand. Other than the required Execute and CanExecute() methods, the interface also requires implementation of CanExecuteChanged event. So CanExecute method would be called in all those instances when the command raises this event. If you look at Josh Smith's implementation of ICommand i.e. RelayCommand, here we are directly hooking it up with CommandManager.RequerySuggested event. Now all user interactions would result in re-evaluation of CanExecute(). But what if the underlying property changes value in response to an event other than any user action. In all those situations, we could face this problem.



We might have different implementations handling this differently. This is quite similarly handler in MVVMLight Libs.



And this is from Prism's DelegateCommand type. That's why we need to call RaiseCanExecuteChanged for DelegateCommand every time we need re-evaluation of CanExecute method.



In order to understand the severity of the problem, let's create a sample WPF application. The following is a sample view model with FirstName property of type string. It also has an ICommand property, SubmitCommand. Here we are using Josh Smith's implementation of ICommand i.e. RelayCommand. The code can be found at his original article on msdn. In the command's CanExecute() method, we are checking if FirstName is null or empty, we are returning false in this case. This should disable the button.


And here is the view which is using the view model, defined above, as its DataContext. It is Binding the FirstName property to a TextBox. Since UpdateSourceTrigger is set as PropertyChanged, it would continue to update the source property as user keeps modifying the text. It also has a button which binds its Command property to view model's SubmitCommand. Now clicking the button should cause running the Execute method of the command. The button should be enabled only when the command's CanExecute() method returns true.


As we are modifying the text in the TextBox, we see that as we empty the TextBox, the button is disabled, which is as expected.



Actually modifying the content of the TextBox cause CommandManager.RequerySuggested to be triggered. Since RelayCommand uses this, it causes CanExecuteChanged event to be triggered. Since the UI framework hooks up to this event. It causes CanExecute to be called.

In order to understand the problem, let's add the following code to our view model. It just flips the value of FirstName property between string.Empty and "Not Empty" literal. Here we expect that as soon as we set it to String.Empty, the button should be disabled. Here we are using a System.Timers.Timer for this purpose. Since Elapsed event is invoked on a ThreadPool thread, the value is being updated without any user interaction on a non-UI thread. Since WPF is very forgiving about PropertyChanged on a non-UI thread, we don't have Dispatcher issues for assigning a value to FirstName in this thread.


Let's run the application and see the result. As shown here, the button is always enabled. This is how we have defined CanExecuteChanged event in RelayCommand. Since MVVMLight's RelayCommand is also defined similarly, we should have the same problem there. For Prism's DelegateCommand, we need to call RaiseCanExecuteChanged(), which raises CanExecuteChanged event for the command.



Now we understand the problem. In the next post, we are going to see how we can resolve it. Stay tuned!

Thursday, August 2, 2012

Portable Class Library & MVVM

This is continued from the previous post where we introduced Portable Library Tools from Microsoft. In this post we will be discussing how useful portable library tools are for the incorporation of MVVM for an application which have multiple UI requirements. The application can be consumed by users from different platforms. These might include Silverlight, WPF, Windows Phone and now Metro. Since all of these platforms can be developed in XAML, we don't need to find many developers with platform specific expertise to develop for a particular platform, keeping in mind that the XAML might be closely similar but same XAML cannot be used for these platforms. It might have a different class hierarchy, different defaults and non-matching behaviors. This also helps in shuffling developers across these teams.

Based on the above discussion, we cannot use same view for these platforms. Back in the days, we couldn't even share the view model across these platforms as many MVVM specific features are not available across these platforms, Or they are not provided similarly. With .Net 4.5 and portable libraries, this gap is being minimized. The features available in one platform is being available in the other platform. It's example is INotifyDataErrorInfo. This used to be available only in Silverlight platform. This is used to notify the errors to the interested UI logic. With .net framework 4.5 Developer's preview, this has been incorporated in .net framework. Before this, we weren't able to share the same view models from silverlight to .net framework because of same reason. Even if we minimize the features to better incorporate multitargeting, we still couldn't use the same assembly across these platforms as the assembly is compiled differently across these frameworks.

Portable Libraries make our lives easier by making only those features available which are supported by all of the selected platforms. If we are targeting our libraries for .net framework 4.5 and Silverlight 4 then only those features would be available which are available in both of these platforms. Let's try to understand this with an example. We are using the same concept of CoffeeHouse application as we have been using for a while. But in order to minimize the noise, we are tasked with a simple interface to enter Barista's information. We only need to provide the details about First and Last name of Barista.

Creating Projects and Adding References
Let's first add a portable class library project for holding view models as follows:


Since this is a portable library based project, we can target multiple platforms. As per the requirement, we are selecting .net framework 4.5 and Silverlight 4 platforms.


Similarly, we add another portable library project to hold our models. This project also targets .net framework 4.5 and Silverlight 4.


Since both model and view model based projects are portable library projects targeting the same platforms, we can add the reference of one in other project. In MVVM view model can hold model's instance when model is not aware of the view model it belongs to. This is similar to Dependency Inversion idea where higher level module (view model) uses lower level modules (models). Here we are adding model project's reference to the view model project.


Now we can add WPF and Silverlight projects for UI logic.


Both of them would need a reference of view model's project so that view model types are available to the UI logic.


The project's references are added as follows:


Please notice that the Silverlight and WPF projects are using the same view model and model's libraries which is the core idea of multitargeting.


Adding Model
Let's add a simple model to Model's project to hold Barista's information. It simply has two properties to hold first and last names of Barista.


Adding View Model
Now we need to add view model. The view model needs to provide the view state. It is responsible for passing the state between view and model at appropriate time. It is also exposing properties for first and last name of the barista. It implements INotifyPropertyChanged to provide value change notification for its properties. The view would be using PropertyChanged event to update itself based on the state of the view model. It also implements INotifyDataErrorInfo for validating the view state. It is supposed to raise ErrorsChanged event whenever error state of a property is updated. The property can be updated from valid to invalid state or vice versa. It is maintaining a collection to hold error details of these properties.

The view model also exposes an ICommand, named SaveBaristaCommand. When executed, this should pass on the view state to the model.


ICommand Implementation for Portable Library Tools
Here we can provide a custom implementation of ICommand in view model's project. This has just been used from Josh's article with minor changes. See the following series of posts from Jeremy to find out how portable class library uses type forwarders to locate the definition of ICommand in a non-SL framework.


Silverlight based UI
Let's add simple interface to enter Barista's information. Let's do it first for Silverlight. It just has two TextBox (es) to enter first and last names of the barista. It also has a button, when clicked the values should be passed to the model.

While running, this should look like as follows:


WPF based Interface
Now let's add WPF based interface to the .net framework 4.5 project. As you might have noticed, the XAML is similar but not same. For silverlight, Label is not available in the framework and we need to use it from the toolkit. In order to minimize the noise there, we ended up using TextBlock(s). Additionally, the default binding Mode is OneWay in Silverlight. Since we need TwoWay binding, we needed to explicitly specify so. We don't need this specification for WPF based XAML as the default here is TwoWay. When you run it, you might miss the error message which is available in Silverlight. this appears when INotifyDataErrorInfo specifies the presence of error for a property. Although the control is highlighted in WPF, we need to provide additional logic to display the actual error message(s).


When executed, this should look like as follows [This is similar to the Silverlight based UI]:


Existing MVVM Frameworks and Toolkits
Although it would be a big relief for most of the developers who are maintaining different versions of their libraries for specific platforms. If they were already writing multitarget enabled code, then they were still using the features which were overlapping across these frameworks. With Portable library tools, this has been taken care for them. We would just need to maintain one set of libraries which support multi-targeting for the selected platforms.

The only caveat is the already existing MVVM frameworks and toolkits which are used heavily for our MVVM designs. Since Portable libraries can only reference other portable libraries supporting the selected frameworks so we wouldn't be able to use the existing frameworks and libraries. As for our code, we needed to provide our own implementation of ICommand [RelayCommand]. Since the portable feature is so promising, I am sure that the frameworks and toolkits authors are already thinking about it.

http://mvvmlight.codeplex.com/SourceControl/network/forks/onovotny/MvvmLightPortable

Download Code

Wednesday, December 21, 2011

WPF 4.5 Developer's Preview - Delay Binding

In this post, let's discuss one great feature of Binding as in WPF 4.5 Developer's preview. This feature is called Delayed Binding. As a XAML technologies developers we are specially concerned about the timing when the values are copied between SOURCE and TARGET of binding.

From the very early stages, human has tried finding answer of this question. Who am I? Even famous eastern poet Bulleh Shah explained in one of his master piece.

Not a believer inside the mosque, am I
Nor a pagan disciple of false rites
Not the pure amongst the impure
Neither Moses, nor the Pharoh
Bulleh! to me, I am not known

Since WPF / Silverlight has very sophisticated Binding, the difference between Source and Target is blurred. Now the main question is what should be called Source and what should be considered as Binding Target. Although the question is not a philosophical one but we clearly need a way to identify the source and target of Binding. Charles Petzold makes it easier by calling Binding Target to be the one where the Binding is actually defined. Now the other party becomes the Binding Source. So if TextBox.Text is bound to FirstName property of the DataContext then TextBox.Text becomes the Binding target and hence DataContext.FirstName might be taken as Binding source.

From Target to Source, we control the timing by using UpdateSourceTrigger property of Binding. As we know that it has three possible modes. PropertyChanged, LostFocus and Explicit.

From Source to Target, this flow of update happens based on the nature of Source property. Generally, the view models implement INotifyPropertyChanged interface. Now setting the property causes PropertyChanged event to be raised. Binding Target listens to this event and update itself. The event has the details which property of the DataContext is updated which makes it easier for the runtime to update the view. The source property might be a DependencyProperty. As we know one of the feature of DependencyProperty is change notification. As WPF runtime receives such notifications, it propagates these changes to the Binding system, which causes updating the target's value.

The direction of flow of these updates are controlled by Binding mode. Different XAML technologies can have different default mode of binding. There are three different Binding modes in WPF / Silverlight. These Binding modes are as follows:

  1. TwoWay
  2. OneWay
  3. OneTime
  4. OneWayToSource
  5. Default
Except possibly Default option, the modes which support flowing the value updates from Target to Source are OneWayToSource and TwoWay. It must be noted that the feature we are discussing in this post only applies to this case when the updates are propagated from Target property to Source property.

Now the main question is why we need this delay? Basically it is to provide a compromise between two selections for UpdateSourceTrigger. These selections are PropertyChanged and LostFocus. With LostFocus, the binding system waits until focus is lost from the target control. So all these intermediate updates are lost. If this is a TextBox, the user might expect immediate response from the system. Since updates are not flowing from Target to source, no converters are applied. Similarly none of the validation rules are used. This might be frustrating for the application's user. On the other hand, if we change this to be using PropertyChanged, all the updates are propagated from Target to Source which might involve value conversion and validation. These operations might cause expensive logic to run. When we are using the control, we don't want to wait until we change focus to the other control. But we, definitely, don't want to run all of this with every key stroke or any other way in which user interaction is causing Target value to be updated. We need a mechanism similar to throttling which helps us in this regard. Binding Delay is just for the same purpose.

Let's create a simple WPF project MVVMDelayedBinding as follows:

Let's add a simple view model. The view model implements INotifyPropertyChanged interface. The view model just has one property FirstName. We will be binding this property to a TextBox in the view. Since we would just be binding this to support the flow of value update from Target to Source, it wouldn't really matter if this supports change notification or not. As a Binding Source, the only requirement is that the source should be a property, change notification support is just to update target from the property updates in the source.

namespace MVVMDelayedBinding
{
    using System.ComponentModel;

    class MainWindowViewModel : INotifyPropertyChanged
    {
        private string _firstName;
        public string FirstName
        {
            get { return _firstName; }
            set
            {
                _firstName = value;
                OnPropertyChanged("FirstName");
            }
        }

        #region INotifyPropertyChanged implementation

        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        private void OnPropertyChanged(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
        
    }
}
Since this is a WPF 4.5 Developer's Preview feature, we need .net framework 4.5 installed on the machine. We also need Visual Studio 11 Developer's Preview. Let's open this in the IDE and update the framework to .net framework 4.5.

Now let's update MainWindow.xaml as follows:

<Window x:Class="MVVMDelayedBinding.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MVVMDelayedBinding"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="45" />
            <RowDefinition Height="auto" />
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="0.20*" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Border Background="Navy" Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" >
            <TextBlock Text="Personal Information" Foreground="White" FontSize="20"
                       TextAlignment="Center" FontWeight="Bold" VerticalAlignment="Center"/>
        </Border>
        <Label Content="First Name" Grid.Row="1" Grid.Column="0" Margin="2,3,2,2"/>
        <TextBox Grid.Row="1" Grid.Column="1" Margin="2,3,2,2" >
            <TextBox.Text>
                <Binding Path="FirstName" 
                         Mode="OneWayToSource" 
                         UpdateSourceTrigger="PropertyChanged"
                         Delay="200" />
            </TextBox.Text>
        </TextBox>
        <Border BorderBrush="Silver" BorderThickness="1" 
                Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="2">
            <TextBlock Text="Other Details" TextAlignment="Center"
                       VerticalAlignment="Center"
                       FontSize="20"/>
        </Border>
    </Grid>
</Window>
This is simple example of MVVM based view. We are using the new MainWindowViewModel instance as the DataContext of the view. The most interesting thing is the TextBox Binding. We are binding the TextBox with FirstName property from the DataContext. The mode is set as OneWayToSource supporting the flow of value updates only from Target to Source. The UpdateSourceTrigger is set as PropertyChanged, resulting in the updates in the Target properties to be copied to the Source without waiting for losing the focus. Now look at the Delay. We are setting the delay as 200. This is in milliseconds. It means the runtime should wait for 200 ms to copy a property update to the Source. This would throttle fast changes to the view and wait for the interaction to get settled before the view state gets updated. Let's run this and use the First Name as Muhammad. Instead of the regular behavior of PropertyChanged. It throttled my input, waited for 200ms and updated the view model's property. This is perfect!

Download:

Friday, August 5, 2011

Binding ObservableCollection to Text Properties

In this post we will be discussing the issue when we bind a collection based (ObservableCollection) property to some scalar DependencyProperty e.g. Text property of a TextBlock.

Let's create a sample MVVM Light based WPF application.


Note:
Yes, you would need an installation of MVVM Light in order to follow this example.

Let's update MainWindow's definition as follows:
<Window x:Class="AppBindingScalarPropertiesCollections.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:converters="clr-namespace:AppBindingScalarPropertiesCollections.Converters"
        mc:Ignorable="d"
        Height="386"
        Width="514"
        Title="MVVM Light Application"
        DataContext="{Binding Main, Source={StaticResource Locator}}">
    
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Skins/MainSkin.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid x:Name="LayoutRoot">
        <Grid.Resources>
            <converters:StudentsListToStringConverter x:Key="studentConverter" />
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="42*" />
            <RowDefinition Height="37*" />
            <RowDefinition Height="189*" />
            <RowDefinition Height="79*" />
        </Grid.RowDefinitions>
        <TextBlock FontSize="36"
                   FontWeight="Bold"
                   Foreground="Purple"
                   Text="{Binding Welcome}"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"
                   TextWrapping="Wrap" Margin="246,104,246,71" Grid.Row="2" />
        <Label Content="New Student" Height="23" HorizontalAlignment="Left"
               Margin="6,15,0,0" Name="label1" VerticalAlignment="Top" Width="97" />
        <TextBox Height="25" HorizontalAlignment="Right" Margin="0,13,12,0"  
                 VerticalAlignment="Top" Width="370"
                 Text="{Binding NewStudentName, UpdateSourceTrigger=PropertyChanged}" />
        <GroupBox Header="Students List" Height="179" HorizontalAlignment="Left" Margin="6,2,0,0" 
                  Name="groupBox1" VerticalAlignment="Top" Width="476" Grid.Row="2">
            <Grid>
                <ListBox ItemsSource="{Binding Students}"  />
            </Grid>
        </GroupBox>
        <GroupBox Header="Comma Separated Students List" Height="57" HorizontalAlignment="Left"
                   VerticalAlignment="Top" Width="476" Grid.Row="3" Margin="0,8,0,0">
            <TextBlock 
                Text="{Binding Students, Converter={StaticResource studentConverter}}" 
                Height="21" />
        </GroupBox>
        <Button Content="Add" Grid.Row="1" Height="26" HorizontalAlignment="Left" 
                Margin="382,7,0,0" VerticalAlignment="Top" Width="99"
                Command="{Binding AddNewStudentCommand}" />
    </Grid>
</Window>
The above view has some expectations from view model. Let's update the view model provided by MVVM Light's view model locator as follows:
namespace AppBindingScalarPropertiesCollections.ViewModel
{
    using GalaSoft.MvvmLight;
    using System.Collections.ObjectModel;
    using System.Windows.Input;
    using GalaSoft.MvvmLight.Command;
  
    public class MainViewModel : ViewModelBase
    {
        public string Welcome
        {
            get
            {
                return "Welcome to MVVM Light";
            }
        }

        string _newStudentName;
        public string NewStudentName
        {
            get { return _newStudentName; }
            set 
            {
                _newStudentName = value;
                RaisePropertyChanged("NewStudentName");
            }
        }

        ObservableCollection<string> _students;
        public ObservableCollection<string> Students
        {
            get
            {
                if (_students == null)
                {
                    _students = new ObservableCollection<string>();
                    _students.Add("Muhammad");
                    _students.Add("Ryan");
                    _students.Add("Jim");
                    _students.Add("Brian");
                    _students.Add("Josh");                   
                    _students.Add("Jeremy");
                }
                return _students;
            }
        }

        ICommand _addNewStudentCommand;
        public ICommand AddNewStudentCommand
        {
            get 
            {
                if (_addNewStudentCommand == null)
                {
                    _addNewStudentCommand = new RelayCommand(
                        () =>
                        {
                            if (!Students.Contains(NewStudentName))
                            {
                                Students.Add(NewStudentName);
                            }
                        });
                }
                
                return _addNewStudentCommand;
            }
        }
    }
}
Mainly it has three things. NewStudentName property to be bound to the TextBox to enter the name of a new student. AddNewStudentCommand
for the button's Command property. Clicking this button should add the student's name as entered in the TextBox to Student's collection if it already doesn't exist. The ListBox and TextBlock showing this are automatically expected be updated as a new student is added to the collection. Students collection to be bound to ListBox's ItemSource and TextBlock's Text properties.

We need the Student's list in the TextBlock to be comma separated names of all students. The view is using a converter for this purpose. It is a simple IValueConverter. Let's see the definition of this converter.
namespace AppBindingScalarPropertiesCollections.Converters
{
    using System.Windows.Data;
    using System.Collections.ObjectModel;
    using System.Linq;

    class StudentsListToStringConverter : IValueConverter
    {
        public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            string studentCommaSeparatedList = string.Empty;
            ObservableCollection<string> studentList = value as ObservableCollection<string>;

            if (studentList != null)
            {
                studentCommaSeparatedList = string.Join(", ",
                                            (from string studentName
                                                 in studentList
                                             select studentName).ToArray<string>());
            }           

            return studentCommaSeparatedList;
        }

        public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new System.NotImplementedException();
        }
    }
}
In the Convert method of this IValueConverter, we are simple joining the elements of the collection with comma separation and returning it.

Let's run the application now. It appears as follows...


As we enter new student's name and hit Add button, the new student is added to Students collection. Since this collection is bound to the ItemsSource of the ListBox, it appears in the list box. But the same does not appear in the TextBlock's comma separated list. This is weird!!!

Basically, the reason is very simple. When we bind to the Text property of TextBlock, it is just interested in the PropertyChanged events. It handles this event to update its contents. But it seems that it doesn't handle CollectionChanged event of ObservableCollection. That is why it is not able to update itself. Now since we know the problem how we can resolve this. Basically there might be two different solutions to this problem.

Solution # 1: [Raise PropertyChanged Event when collection is updated for items]

This is very simple. Since we are just adding items in the Execute method of the ICommand bound to the Add button, we can simply do it there. Let's update the ICommand definition in the view model as follows:
public ICommand AddNewStudentCommand
{
    get 
    {
        if (_addNewStudentCommand == null)
        {
            _addNewStudentCommand = new RelayCommand(
                () =>
                {
                    if (!Students.Contains(NewStudentName))
                    {
                        Students.Add(NewStudentName);
                        RaisePropertyChanged("Students");
                    }
                });
        }
        
        return _addNewStudentCommand;
    }
}
Here RaisePropertyChanged method raises PropertyChanged event for the name of property provided as argument. This is available due to inheritence of this view model by ViewModelBase from MVVM Light. Let's run the application again.


As we entered Sekhar and hit the button, it appears both in the ListBox and TextBlock. This is exactly what we desired. Zindabad!!!

2nd Solution: [Use MultiBinding, adding binding for ObservableCollection.Count]
In this solution, we can simply add binding for Count property from the same collection. We can change the binding of TextBlock as follows:
<Window x:Class="AppBindingScalarPropertiesCollections.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:converters="clr-namespace:AppBindingScalarPropertiesCollections.Converters"
        mc:Ignorable="d"
        Height="386"
        Width="514"
        Title="MVVM Light Application"
        DataContext="{Binding Main, Source={StaticResource Locator}}">
    
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Skins/MainSkin.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>

    <Grid x:Name="LayoutRoot">
        <Grid.Resources>
            <converters:StudentListToStringMultiConverter x:Key="studentMultiConverter" />
        </Grid.Resources>
        <Grid.RowDefinitions>
            <RowDefinition Height="42*" />
            <RowDefinition Height="37*" />
            <RowDefinition Height="189*" />
            <RowDefinition Height="79*" />
        </Grid.RowDefinitions>
        <TextBlock FontSize="36"
                   FontWeight="Bold"
                   Foreground="Purple"
                   Text="{Binding Welcome}"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"
                   TextWrapping="Wrap" Margin="246,104,246,71" Grid.Row="2" />
        <Label Content="New Student" Height="23" HorizontalAlignment="Left"
               Margin="6,15,0,0" Name="label1" VerticalAlignment="Top" Width="97" />
        <TextBox Height="25" HorizontalAlignment="Right" Margin="0,13,12,0"  
                 VerticalAlignment="Top" Width="370"
                 Text="{Binding NewStudentName, UpdateSourceTrigger=PropertyChanged}" />
        <GroupBox Header="Students List" Height="179" HorizontalAlignment="Left" Margin="6,2,0,0" 
                  Name="groupBox1" VerticalAlignment="Top" Width="476" Grid.Row="2">
            <Grid>
                <ListBox ItemsSource="{Binding Students}"  />
            </Grid>
        </GroupBox>
        <GroupBox Header="Comma Separated Students List" Height="57" HorizontalAlignment="Left"
                   VerticalAlignment="Top" Width="476" Grid.Row="3" Margin="0,8,0,0">

            <TextBlock                 
                Height="21" >
                <TextBlock.Text>
                    <MultiBinding  Converter="{StaticResource studentMultiConverter}" >
                        <Binding Path ="Students"/>
                        <Binding Path ="Students.Count" />
                    </MultiBinding>
                </TextBlock.Text>
            </TextBlock>
        </GroupBox>
        <Button Content="Add" Grid.Row="1" Height="26" HorizontalAlignment="Left" 
                Margin="382,7,0,0" VerticalAlignment="Top" Width="99"
                Command="{Binding AddNewStudentCommand}" />
    </Grid>
</Window>
In addition of Binding update, we also need to update the converter to IMultiValueConverter. Let's see the definition of StudentListToStringMultiConverter used above.
class StudentListToStringMultiConverter : IMultiValueConverter
{

    public object Convert(object[] values, System.Type targetType, object parameter, 
        System.Globalization.CultureInfo culture)
    {
        string studentCommaSeparatedList = string.Empty;
        ObservableCollection<string> studentList = values[0] as ObservableCollection<string>;

        if (studentList != null)
        {
            studentCommaSeparatedList = string.Join(", ",
                                        (from string studentName
                                             in studentList
                                         select studentName).ToArray<string>());
        }

        return studentCommaSeparatedList;
    }

    public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter,
        System.Globalization.CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }
}
Running the application should have the same result as the first option.

Any Questions??? Comments...

Download:
The sameple project can be downloaded from SkyDrive here:

Friday, March 25, 2011

WPF: Configuring System.Runtime.Caching.MemoryCache for an MVVM based App

This is a continuation of our post here:

http://shujaatsiddiqi.blogspot.com/2011/03/wpf-performance-improvement-for-mvvm.html

In the above post we discussed how we can use the new caching feature available in .net framework 4.0 to improve the performance of a WPF application. As an example we used an application implementing MVVM pattern. In this example we would extend the example by discussing how we can use configuration option provided with this caching feature. We would also look at the underlying architecture provided by the framework to support this.

As we discussed in the previous example, the framework has provided MemoryCache. This is an implementation of ObjectCache providing an in-memory caching mechanism. Let us create a simple view showing the fields from this cache.

In order to use this you need to add a reference of System.Runtime.Caching assembly from the framework.

Yes I have Power Tools installed :).
<Window x:Class="WPF_MVVM_Caching.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WPF_MVVM_Caching"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Label Content="PollingInterval" Height="26" HorizontalAlignment="Left" 
               Margin="10,21,0,0" Name="label1" VerticalAlignment="Top" Width="141" />
        <TextBlock Height="26" HorizontalAlignment="Left" Margin="157,21,0,0" Name="txtPollingInterval"
                   Background="LightGoldenrodYellow"
                   Text="{Binding PollingInterval, Mode=OneTime}" VerticalAlignment="Top" Width="302" />
        <Label Content="PhysicalMemoryLimit" Height="26" HorizontalAlignment="Left" 
               Margin="10,53,0,0" Name="label2" VerticalAlignment="Top" Width="141" />
        <TextBlock Background="LightGoldenrodYellow" Height="26" HorizontalAlignment="Left" 
                   Margin="157,53,0,0" Name="txtPhysicalMemoryLimit" Text="{Binding PhysicalMemoryLimit, Mode=OneTime}" 
                   VerticalAlignment="Top" Width="302" />
        <Label Content="Name" Height="26" HorizontalAlignment="Left" 
               Margin="11,85,0,0" Name="label3" VerticalAlignment="Top" Width="140" />
        <TextBlock Background="LightGoldenrodYellow" Height="26" HorizontalAlignment="Left" 
                   Margin="157,85,0,0" Name="txtName" Text="{Binding Name, Mode=OneTime}" 
                   VerticalAlignment="Top" Width="302" />
        <Label Content="CacheMemoryLimit" Height="26" HorizontalAlignment="Left" 
               Margin="10,116,0,0" Name="label4" VerticalAlignment="Top" Width="141" />
        <TextBlock Background="LightGoldenrodYellow" Height="26" HorizontalAlignment="Left" 
                   Margin="157,116,0,0" Name="txtCacheMemoryLimit" Text="{Binding CacheMemoryLimit, Mode=OneTime}" 
                   VerticalAlignment="Top" Width="302" />
    </Grid>
</Window>

The view is expecting certain properties from MainWindowViewModel which is used as its DataContext. They are bound with Text properties of TextBlocks. The definition of MainWindowViewModel is as follows:
namespace WPF_MVVM_Caching
{
    using System.ComponentModel;
    using System.Runtime.Caching;

    class MainWindowViewModel : INotifyPropertyChanged
    {
        public string CacheMemoryLimit
        {
            get { return string.Format("{0}", MemoryCache.Default.CacheMemoryLimit); }
        }

        public string PollingInterval
        {
            get { return string.Format("{0}", MemoryCache.Default.PollingInterval); }
        }

        public string PhysicalMemoryLimit
        {
            get { return string.Format("{0}", MemoryCache.Default.PhysicalMemoryLimit); }
        }

        public string Name
        {
            get { return MemoryCache.Default.Name; }
        }

        #region INotifyPropertyChanged Implementation
        
        public event PropertyChangedEventHandler PropertyChanged = delegate { };
        private void onPropertyChanged(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion INotifyPropertyChanged Implementation
    }
}


Loading Default Memory Cache with Configuration Options:
The configuration of default MemoryCache is easy. We just need to provide the following code in the app.config file and the framework automatically loads the MemoryCache with the specified values as in the configuration file.
<?xml version="1.0"?>
<configuration>
  <system.runtime.caching>
    <memoryCache>
      <namedCaches>
        <add name="Default"
             cacheMemoryLimitMegabytes="52"
             physicalMemoryLimitPercentage="40"
             pollingInterval="00:04:01" />
      </namedCaches>
    </memoryCache>
  </system.runtime.caching>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>
Now run the application. We can see that the MemoryCache.Default is constructed with the values that we specified in the configuration file. The view would appear as follows:


So in order to provide the definition of the Default MemoryCache configuration, we just need to make sure that we use name Default and provide the values for the properties that we want to change. The properties not specified in configuration would be kept with default values.

Configuring Non-Default Caches:
In the above example we have seen how we can configure the Default MemoryCache. We can use the same technique to configure a non-default cache. We might be needing it when we want to define a local cache. In order to instantiate a non-default cache, whose properties expected to be loaded from a configuration file, MemoryCache provides a constructor. We need to provide the name of cache configuration to use to construct the cache instance as follows:
<?xml version="1.0"?>
<configuration>
  <system.runtime.caching>
    <memoryCache>
      <namedCaches>
        <add name="TestCache"
             cacheMemoryLimitMegabytes="52"
             physicalMemoryLimitPercentage="40"
             pollingInterval="00:04:01" />
      </namedCaches>
    </memoryCache>
  </system.runtime.caching>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/>
  </startup>
</configuration>
We can use this cache as follows:
class MainWindowViewModel : INotifyPropertyChanged
{
    MemoryCache cache;

    public MainWindowViewModel()
    {
        cache = new MemoryCache("TestCache");
        //string s = "";
    }

    public string CacheMemoryLimit
    {
        get { return string.Format("{0}", cache.CacheMemoryLimit); }
    }

    public string PollingInterval
    {
        get { return string.Format("{0}", cache.PollingInterval); }
    }

    public string PhysicalMemoryLimit
    {
        get { return string.Format("{0}", cache.PhysicalMemoryLimit); }
    }

    public string Name
    {
        get { return cache.Name; }
    }

    #region INotifyPropertyChanged Implementation
    
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    private void onPropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion INotifyPropertyChanged Implementation
}
When we run the application we can see that the properties are successfully loaded from the configuration and the view is shown as follows:


System.Runtime.Caching.Configuration in Details
Now let us look at the underlying architecture used by the above logic. The configuration classes for run-time caching is provided in System.Runtime.Caching.Configuration namespace in System.Runtime.Caching assembly. They are based on the same logic we implement when we want configuration option for some classes i.e. We have to define classes inheriting from the following classes:

- ConfigurationElement
- ConfigurationElementCollection
- ConfigurationSection
- ConfigurationSectionGroup

For System.Runtime.Caching, these classes are as follows:
- MemoryCacheElement
- MemoryCacheSettingsCollection
- MemoryCacheSection
- CachingSectionGroup

They can be shown in the class diagram as follows:



Now in order to go further with this example we need to add a reference of System.Configuration assembly as follows:


Let us update the configuration file as follows:
<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="MemoryCacheConfiguration"
                  type="System.Runtime.Caching.Configuration.MemoryCacheSection, System.Runtime.Caching, Version= 4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  </configSections>
  <MemoryCacheConfiguration>
    <namedCaches>
      <add name="MyMemoryCache" physicalMemoryLimitPercentage="23"
            pollingInterval="00:04:43" cacheMemoryLimitMegabytes="123" />
    </namedCaches>
  </MemoryCacheConfiguration>
</configuration>
Here we have defined a section named MemoryCacheConfiguration for System.Runtime.Caching.MemoryCacheSection type. Later we have provided the details about MemoryCacheConfiguration with details about runtime cache.

Now we instantiate a memory cache based on the information provided here in the configuration file. We can update the view model's constructor as follows:
public MainWindowViewModel()
{
    //Get Configuration section info from Configuration
    MemoryCacheSection section = (MemoryCacheSection)ConfigurationManager.GetSection("MemoryCacheConfiguration");

    //Create a name / value pair for properties
    NameValueCollection configurationNameValueCollection = new NameValueCollection();
    configurationNameValueCollection.Add("pollingInterval", 
        string.Format("{0}", section.NamedCaches[0].PollingInterval));
    configurationNameValueCollection.Add("physicalMemoryLimitPercentage", 
        string.Format("{0}", section.NamedCaches[0].PhysicalMemoryLimitPercentage));
    configurationNameValueCollection.Add("cacheMemoryLimitMegabytes", 
        string.Format("{0}", section.NamedCaches[0].CacheMemoryLimitMegabytes));
    
    //instantiate cache
    cache = new MemoryCache(section.NamedCaches[0].Name, configurationNameValueCollection);
}
Now let us run the application. The view should appear as follows:


Download Code:

Thursday, March 17, 2011

WPF - Performance Improvement for MVVM Based Applications - Part # 3

This is third part of our discussion about .net features and techniques to improve the performance of MVVM based applications. The other part of this discussion are:

Part 1: http://shujaatsiddiqi.blogspot.com/2011/01/wpf-performance-improvement-for-mvvm.html

Part 2: http://shujaatsiddiqi.blogspot.com/2011/02/wpf-performance-improvement-for-mvvm.html

In this post we will be discussing how we can use Caching to improve the performance of an application. Support of Caching in desktop application is a new feature of .net framework 4.0.

Assembly and Namespace:
Most of the classes used for caching feature are available in System.Runtime.Caching namespace available in System.Runtime.Caching assembly. We need to add an assembly reference of this assembly in order to use these types.


Extensible Caching Implementation:
The cache system available in .net 4.0 has been implemented from ground up to be an extensible concept. A Cache provider must inherit from ObjectCache available in System.Runtime.Caching namespace. The cache provider available with .net is MemoryCache. It represents an in-memory cache. This is similar to ASP.net cache but you don't need to use System.Web.Caching as it is available in the same System.Runtime.Caching namespace in System.Runtime.Caching assembly. The other benefit is that we can create multiple instances of MemoryCache in the same AppDomain.


Simple Caching Usage for temporal locality of reference:
Let's consider an example of a WPF application using this. In this example we would be utilizing the idea of temporal locality of reference. We would be reading the contents of a File. Since I/O is a time consuming operation, we will be caching the contents of the file. We will be using this cached content from other window, where we would be showing it in a TextBlock. The definition of MainWindow is as follows:
<Window x:Class="WpfApp_MVVM_Caching.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp_MVVM_Caching"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <TextBlock Height="81" HorizontalAlignment="Left" Margin="12,17,0,0" 
                   Name="textBlock1" Text="{Binding FileContents}" VerticalAlignment="Top" Width="468" />
        <Button Content="Open Child Window" Height="26" HorizontalAlignment="Left" Margin="12,273,0,0" Name="btnOpenChildWindow" 
                VerticalAlignment="Top" Width="134" Click="btnOpenChildWindow_Click" />
    </Grid>
</Window>
This window has a TextBlock to display the contents of the file. The Text property of this TextBlock is bound to FileContents property of DataContext. The window also has a button. The definition of click event handler [btnOpenChildWindow_Click] from the code behind is as follows:
private void btnOpenChildWindow_Click(object sender, RoutedEventArgs e)
{
    new ChildWindow().Show();
}
This is just opening the ChildWindow as a modeless window using its Show method. MainWindow is using MainWindowViewModel instance as its DataContext. It is constructing its instance as part of its initialization code. The definition of MainWindowViewModel is as follows:
class MainWindowViewModel : INotifyPropertyChanged
{

    public MainWindowViewModel()
    {
        string localfileContents = File.ReadAllText(@"C:\Users\shujaat\Desktop\s.txt");
        FileContents = localfileContents;

        MemoryCache.Default.Set("filecontents", localfileContents, DateTimeOffset.MaxValue);
    }

    #region Properties
    
    private string _fileContents;
    public string FileContents
    {
        get { return _fileContents; }
        set
        {
            _fileContents = value;
            OnPropertyChanged("FileContents");
        }
    }

    #endregion

    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion INotifyPropertyChanged implementation

}
As expected by the view, It just has a property FileContents. In the constructor, the contents of a file is read and assigned to this property. Since this is based on INotifyPropertyChanged, the changes are propagated to the view using PropertyChanged event. Additionally, we are copying the data read from the file to MemoryCache.Default with Key 'fileconents'.

The definition of ChildWindow is as follows:
<Window x:Class="WpfApp_MVVM_Caching.ChildWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp_MVVM_Caching"
        Title="Child Window" Height="300" Width="300">
    <Window.DataContext>
        <local:ChildWindowViewModel />
    </Window.DataContext>
    <Grid>
        <TextBlock Height="61" HorizontalAlignment="Left" Margin="36,49,0,0" Name="textBlock1" 
                   VerticalAlignment="Top" Width="206" Text="{Binding CacheEntryValue}" />
    </Grid>
</Window>
It has a TextBlock whose Text property is bound to CacheEntryValue property from the DataContext. The DataContext is an instance of ChildWindowViewModel. Its definition is as follows:
class ChildWindowViewModel : INotifyPropertyChanged
{
    private string _cacheEntryValue;
    public string CacheEntryValue
    {
        get { return _cacheEntryValue; }
        set
        {
            _cacheEntryValue = value;
            OnPropertyChanged("CacheEntryValue");
        }
    }

    public ChildWindowViewModel()
    {
        CacheEntryValue = MemoryCache.Default["filecontents"] as string;
    }

    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion INotifyPropertyChanged implementation
}
We are just copying the contents of the cache entry defined in the MainWindow to the Text property of the TextBlock. Using the value is achieved using the idea of temporal locality of Caching technology. Let's run the application and open child window.


As you might already have guessed, the contents of the file are: "Muhammad Shujaat Siddiqi".

Changes in Underlying DataSource:
Cache keeps the data available in an application for faster data access when it is needed. The user of this cache might or might not know about the actual data source. The caching feature available in .net framework 4.0 keeps track of this is through the provision of ChangeMonitor. This is basically kind of implementation of Observer design pattern. So when underlying datasource is changed, the ChangeMonitor notifies the ObjectCache implemenation [MemoryCache] about this change. ObjectCache implementation then takes any action about this change. It might even nullify the Cache entry as it is invalid now [Like the case of MemoryCache].


Let us create a new Window to present an example of a WPF application using ChangeMonitor. The Window below is a similar window as the above example. It just has an extra TextBox and a Button.
<Window x:Class="WpfApp_MVVM_Caching.MainWindowChangeMonitorExample"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp_MVVM_Caching"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowChangeMonitorExampleViewModel />
    </Window.DataContext>
    <Grid>
        <TextBlock Height="81" HorizontalAlignment="Left" Margin="12,17,0,0" 
                   Name="textBlock1" Text="{Binding FileContents}" VerticalAlignment="Top" Width="468" />
        <TextBox Height="138" HorizontalAlignment="Left" Margin="279,125,0,0" Name="textBoxCachedFileContents"
                 VerticalAlignment="Top" Width="212" Text="{Binding Path=MessageToDataSource, UpdateSourceTrigger=PropertyChanged}" />
        <Button Content="Update Data Source" Height="30" HorizontalAlignment="Left" 
                Margin="314,269,0,0" Name="btnUpdateDataSource" VerticalAlignment="Top" 
                Width="177" Command="{Binding UpdateDataSourceCommand}" />
        <Button Content="Open Child Window" Height="26" HorizontalAlignment="Left" Margin="12,273,0,0" Name="btnOpenChildWindow" 
                VerticalAlignment="Top" Width="134" Click="btnOpenChildWindow_Click" />
    </Grid>
</Window>
The above view is using a new instance of MainWindowChangeMonitorExampleViewModel as its DataContext. It is expecting a string property FileContents to bind to the Text property of the TextBlock. Additionally, it is also expecting the DataContext to have MessageToDataSource property to bind to the Text property of the only TextBox. When a user clicks the Update button the contents of TextBox should be updated to the DataSource (File). Since FileContents are invalid now, it should be updated to the latest contents. For that, the view model should use ChangeMonitor. But first look at the code behind of this view.
public partial class MainWindowChangeMonitorExample : Window
{
    public MainWindowChangeMonitorExample()
    {
        InitializeComponent();
    }

    private void btnOpenChildWindow_Click(object sender, RoutedEventArgs e)
    {
        new ChildWindow().Show();
    }
}
This is similar to the view in the previous examples. When user clicks "Open Child Window", a new instance of ChildWindow is shown in a modeless fashion. Now we have a look at the View Model. Get ready to see Change Monitors in action...
class MainWindowChangeMonitorExampleViewModel : INotifyPropertyChanged
{
    #region Fields

    List<string> filePaths = new List<string>();

    #endregion Fields

    #region Constructors

    public MainWindowChangeMonitorExampleViewModel()
    {
        filePaths.Add(@"C:\Users\shujaat\Desktop\s.txt");
        
        string localfileContents = File.ReadAllText(@"C:\Users\shujaat\Desktop\s.txt");
        FileContents = localfileContents;

        var changeMonitor = new HostFileChangeMonitor(filePaths);
        var policy = new CacheItemPolicy();

        MemoryCache.Default.Set("filecontents", localfileContents, policy);
                                 
        policy.ChangeMonitors.Add(changeMonitor);            
        changeMonitor.NotifyOnChanged(OnDataSourceUpdated);

    }

    #endregion Constructors

    #region Change Monitor Callback

    private void OnDataSourceUpdated(Object State)
    {
        //Get file contents
        FileInfo file = new FileInfo(@"C:\Users\shujaat\Desktop\s.txt");
        using (FileStream stream = file.OpenRead())
        {
            using (StreamReader reader = new StreamReader(stream))
            {
                string updatedFileContents = reader.ReadToEnd();
                reader.Close();
                FileContents = updatedFileContents;
            }
        }

        //Update Cache Entry
        MemoryCache.Default["filecontents"] = FileContents;

        //Update change monitor for further changes in file contents
        var policy = new CacheItemPolicy();
        var changeMonitor = new HostFileChangeMonitor(filePaths);
        policy.ChangeMonitors.Add(changeMonitor);
        changeMonitor.NotifyOnChanged(OnDataSourceUpdated);
    }

    #endregion Change Monitor Callback

    #region Properties

    private string _fileContents;
    public string FileContents
    {
        get { return _fileContents; }
        set
        {
            _fileContents = value;
            OnPropertyChanged("FileContents");
        }
    }

    private string _messageToDataSource;
    public string MessageToDataSource
    {
        get { return _messageToDataSource; }
        set
        {
            _messageToDataSource = value;
            OnPropertyChanged("MessageToDataSource");
        }
    }

    #endregion

    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion INotifyPropertyChanged implementation

    #region Commands

    ICommand _updateDataSourceCommand;
    public ICommand UpdateDataSourceCommand
    {
        get
        {
            if (_updateDataSourceCommand == null)
            {
                _updateDataSourceCommand = new RelayCommand(
                    param => this.UpdateDataSource(),
                    param => this.CanUpdateDataSource
                    );
            }
            return _updateDataSourceCommand;
        }
    }

    public void UpdateDataSource()
    {
        FileInfo file = new FileInfo(@"C:\Users\shujaat\Desktop\s.txt");
        using (FileStream stream = file.OpenWrite())
        {
            using (StreamWriter writer = new StreamWriter(stream) { AutoFlush = true })
            {
                writer.Write(MessageToDataSource);
                writer.Close();
            }
        }
    }

    bool CanUpdateDataSource
    {
        get { return true; }
    }

    #endregion Commands
}
In the constructor, like in the previous example, it is reading the contents of a text file and adding it to the cache. Additionally, it is creating a HostFileChangeMonitor and adds it the CacheItemPolicy's list of ChangeMonitors. This policy is being used for keeping a watch on the contents of the files specified by the ChangeMonitors. If there is an update, it executes the callback as specified by the ChangeMonitor. HostFileChangeMonitor is a descendent of ChangeMonitor through FileChangeMonitor. In non ASP.net applications, it uses internally FileSystemWatcher to monitor files. It must be remembered that it does not support relative paths.

As expected by the view, it has two string properties FileContents and MessageToDataSource. It also has a RelayCommand object UpdateDataSourceCommand. This command is executed when user clicks Update Data Source button. In the execute method [UpdateDataSource] of this command, we are just updating the contents of the file using StreamWriter.

The soul of this example is OnDataSourceUpdated method specified as the callback for change notification in the monitored data sources by HostFileChangeMonitor. When the contents of the file are updated, this method gets called. In this method we are updating the Cache Entry and the string property bound to the text block in the view showing the contents of the file.

Now specify the new view as startup view of the project in App.xaml and run the application. The view appears as follows:


Now let us update the contents of the TextBox and click "Update Data Source" button. As the contents of the file are updated, the callback is called by the ChangeMonitor which updates the cache entry and the FileContent property with updated contents of the file. Since this is bound to a TextBlock.TextProperty in the view, the view shows this update.


Now we open the child window using "Open Child Window" button. The child window uses the same cache entry. The child window appears as follows:


Now update the contents of file again by updating the contents of the TextBox and hitting "Update Data Source" button. This should be done when the ChildWindow is still shown. We are updating the contents with one of Jalal Uddin Rumi's great quote.


Cache Entry Change Monitor:

As you can see that clicking Update Source button after updating the contents of the TextBox updates the TextBlock on the main window but it does not appear to update the contents of second window. This is because the ChildWindow does not know that the cache entry value it used for its TextBlock has been updated. If ChildWindow has some means to get notification for this cache entry update then it could update its logic. For this purpose we can use another ChangeMonitor, called CacheEntryChangeMonitor.

Let's update the constructor of ChildWindowViewModel as follows:
public ChildWindowViewModel()
{
    CacheEntryValue = MemoryCache.Default["filecontents"] as string;
    MemoryCache.Default.CreateCacheEntryChangeMonitor(
        new string[] { "filecontents" }.AsEnumerable<string>()).NotifyOnChanged((a) =>
        {
            CacheEntryValue = MemoryCache.Default["filecontents"] as string;
        }
    );
}
Here we have just added an instane CacheEntryChangeMonitor to the code. Again we are using the same cache entry but the only difference we have added a NotifyOnChanged callback for this. As the entry gets updated this callback is called and it updates the property bound to the TextBlock.Text property in the view refreshing this.


Download Code:

Saturday, March 5, 2011

WPF - Binding InputBindings to View Model Commands using MVVM

In this post we will be discussing about how we can bind mouse and key gestures directly with Commands in the view model. Generally when we talk about this type of binding we end up using RoutedCommand directly in the view having Execute and CanExecute methods in the view itself. This is a new feature of WPF 4.

In order to understand this, let's consider a sample application with some input bindings. When the particular key combination are received by WPF runtime, it should update properties in view model. These properties supports change notifications by implementing INotifyPropertyChanged interface.
<Window x:Class="WpfApplication_InputBindings_MVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication_InputBindings_MVVM"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Window.InputBindings>
        <KeyBinding Key="F2" Modifiers="Control" Command="{Binding OperationCommand}" />
    </Window.InputBindings>    
    <Grid>
        <Label Content="Message" Height="26" HorizontalAlignment="Left" Margin="12,47,0,0" 
               Name="label1" VerticalAlignment="Top" Width="67" FontWeight="Bold" />
        <TextBlock Height="27" HorizontalAlignment="Left" Margin="86,53,0,0" 
                   Name="textBlockMessage" Text="{Binding Message}" VerticalAlignment="Top" Width="405" />
    </Grid>
</Window>
In the above view we have added KeyBinding for "Ctrl + F2" key combination. The view model should have a command OperationCommand. When user presses the specified key combination, it should execute the command methods on the view model. The view is using a new instance of MainWindowViewModel as its DataContext. It is also binding Text property of the only TextBlock to a property Message from the DataContext.

Let's look at the definition of MainWindowViewModel. Since it needs to support Property change notification to the view, it is using one of the available change notification system. It is using this mechanism for its Message property. As part of its contract for INotifyPropertyChanged, it provides an event PropertyChanged. We have used RelayCommand for supporting command execution from view model [http://msdn.microsoft.com/en-us/magazine/dd419663.aspx].
class MainWindowViewModel : INotifyPropertyChanged
{
    #region Operation Command
    
    RelayCommand _operationCommand;
    public ICommand OperationCommand
    {
        get
        {
            if (_operationCommand == null)
            {
                _operationCommand = new RelayCommand(param => this.ExecuteCommand(),
                    param => this.CanExecuteCommand);
            }
            return _operationCommand;
        }
    }

    public void ExecuteCommand()
    {
        Message = "Command Executed";
    }

    bool CanExecuteCommand
    {
        get { return true; }
    }
    
    #endregion Operation Command

    #region Properties

    private string _message;
    public string Message
    {
        get { return _message; }
        set
        {
            _message = value;
            OnPropertyChanged("Message");
        }
    }

    #endregion Properties

    #region INotifyPropertyChanged implementation

    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    private void OnPropertyChanged(string propertyName)
    {
        PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }

    #endregion INotifyPropertyChanged implementation
}
When we run the application and hit the specified key combination, it first checks if the command is eligible for execution from CanExecuteCommand property. If it returns true then it executes ExecuteCommand method. In this method we are setting Message property to "Command Executed". Since this property supports change notification so the same changes are updated on the view.

Let us run this now. The application is displayed as follows:


As expected, When we press Ctrl + F2 key combination the view is updated as follows:


Stealing Key Gestures from Application Commands:
Still we have simple command bound to the Window. What if we have a command with key gestures from default Commands available by the framework including ApplicationCommands? Now let's progress this example into a little complex one. Let's change the input bindings to a key gestures Ctrl + V.
<Window x:Class="WpfApplication_InputBindings_MVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication_InputBindings_MVVM"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Window.InputBindings>
        <KeyBinding Key="V" Modifiers="Control" Command="{Binding OperationCommand}" />
    </Window.InputBindings>    
    <Grid>
        <Label Content="Message" Height="26" HorizontalAlignment="Left" Margin="12,47,0,0" 
               Name="label1" VerticalAlignment="Top" Width="67" FontWeight="Bold" />
        <TextBlock Height="27" HorizontalAlignment="Left" Margin="86,53,0,0" 
                   Name="textBlockMessage" Text="{Binding Message}" VerticalAlignment="Top" Width="405" />
        <TextBox Height="29" HorizontalAlignment="Left" Margin="82,152,0,0" Name="textBox1" 
                 VerticalAlignment="Top" Width="409" />
    </Grid>
</Window>
In the above XAML, we have updated the key gestures to Ctrl + V. We move focus to the new TextBox and hit Ctrl + V [I have text "Muhammad Siddiqi" copied to clip board].


You can see that TextBox has stolen the key gestures. This has resulted in the text on the clip board being pasted to the Text Box. This is because of default paste command using this key gesture for the text box.

Binding Key Gesture of un-wanted command to ApplicationCommands.NotACommand:
The first solution is very simple. We can just assign those key gestures to ApplicationCommands.NotACommand. We can achieve the same using CommandManager available in System.Windows.Input namespace. Let's update the constructor of the view as follows:
public MainWindow()
{
    InitializeComponent();

    CommandManager.RegisterClassInputBinding(typeof(UIElement),
        new InputBinding(ApplicationCommands.NotACommand, 
            new KeyGesture(Key.V, ModifierKeys.Control)));
}
Now let's run the application again. When we hit Ctrl + V the command actually executes and key gestures are not stolen by Paste Command for the text box.


This approach seems to be working but it has a few limitations. First this is application wide i.e. this gesture is stolen for the whole application. The other thing is that we can not un-register this.

Vote: http://connect.microsoft.com/VisualStudio/feedback/details/481627/no-way-to-unregister-a-commandmanager-registerclasscommandbinding

Handling CanExecute Tunneling Event:
The other solution is to handle PreviewCanExecute event of the command causing the key gesture conflict. In the following example we are using CommandBinding to provide tunneling event handler for CanExecute for Paste Command. Since CommandBindings, unlike InputBindings, is a DependencyProperty if this command is handled above in the logical hierarchy this wouldn't be propagating down. Let's update XAML as follows:
<Window x:Class="WpfApplication_InputBindings_MVVM.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApplication_InputBindings_MVVM"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Window.InputBindings>
        <KeyBinding Key="V" Modifiers="Control" Command="{Binding OperationCommand}" />
    </Window.InputBindings>    
    <Window.CommandBindings>
        <CommandBinding Command="Paste" PreviewCanExecute="CommandBinding_PreviewCanExecute" />
    </Window.CommandBindings>
    <Grid>
        <Label Content="Message" Height="26" HorizontalAlignment="Left" Margin="12,47,0,0" 
               Name="label1" VerticalAlignment="Top" Width="67" FontWeight="Bold" />
        <TextBlock Height="27" HorizontalAlignment="Left" Margin="86,53,0,0" 
                   Name="textBlockMessage" Text="{Binding Message}" VerticalAlignment="Top" Width="405" />
        <TextBox Height="29" HorizontalAlignment="Left" Margin="82,152,0,0" Name="textBox1" 
                 VerticalAlignment="Top" Width="409" />
    </Grid>
</Window>
Let's see the definition of CommandBinding_PreviewCanExecute:
private void CommandBinding_PreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)
{
    e.Handled = true;
}
If we run this now and hit Ctrl + V by setting focus on the text box, this event handler is executed. Since this is handled here this would not be propagated to the text box. The view is updated as follows:


Download Code: