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:

Wednesday, March 2, 2011

Rx - Executing IObservable in Parallel in a WPF application

In this post we are going to take the asynchronous code execution using Reactive extension a bit further. We would see how we can have multiple IObservable (s) are executed in parallel. Rx supports this using Observable.ForkJoin. We can have code executed in parallel which doesn't return any data, return same or different data.

It's not blocking rather still asynchronous:
Let's create a simple view with a single message and a button. We need to execute the IObservable in parallel when button is clicked.
<Window x:Class="WpfApp_Reactive_ForkJoin.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp_Reactive_ForkJoin"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <TextBlock Height="47" HorizontalAlignment="Left" Margin="70,63,0,0" 
                   Name="textBlock1" Text="{Binding Message}" VerticalAlignment="Top" Width="384" />
        <Button Content="Start Operations" Height="38" HorizontalAlignment="Left" Margin="68,134,0,0"
                Name="btnStartOperations" VerticalAlignment="Top" Width="143" 
                Command="{Binding OperationCommand}"/>
    </Grid>
</Window>
The view is assigning an instance of MainWindowViewModel as the DataContext of the Window. The view expects Message property from the view model to bind it to the Text property of the TextBlock. It also expects an ICommand OperationCommand in the view model. We are implementing INotifyPropertyChanged so we need to provide PropertyChanged event in this view model. It has Message property which is bound to the Text property of the TextBlock in the view.
class MainWindowViewModel : INotifyPropertyChanged
{
    #region Constructor
    public MainWindowViewModel()
    {

    }
    #endregion Constructor

    #region Public Properties

    string _message = "Operation not started yet...";
    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

    #region Operation Command

    RelayCommand _operationCommand;
    public ICommand OperationCommand
    {
        get
        {
            if (_operationCommand == null)
            {
                _operationCommand = new RelayCommand(param => this.StartOperation(),
                    param => this.CanStartOperation);
            }
            return _operationCommand;
        }
    }

    bool CanStartOperation
    {
        get
        {
            return true;
        }
    }

    [DebuggerHidden]
    public void StartOperation()
    {
        Message = "Operation running";

        Observable.ForkJoin(
            Observable.Start(() => { 
                                       Message = "In 1st Observable.Start";
                                       Debug.WriteLine("Executing 1st on Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                                       Thread.Sleep(2000);
                                   }),
            Observable.Start(() => { 
                                       Message = "In 2nd Observable.Start";
                                       Debug.WriteLine("Executing 2nd on Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                                       Thread.Sleep(2000);
                                   }),
            Observable.Start(() => { 
                                       Message = "In 3rd Observable.Start";
                                       Debug.WriteLine("Executing 3rd on Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                                       Thread.Sleep(10000);
                                       throw new System.Exception("exception");
                                   })
            )
            .Subscribe(
                        (result) => { 
                                        Message = result.ToString();
                                        Debug.WriteLine("OnNext: Executing 1st on Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                                        Thread.Sleep(2000); 
                                    },
                        (ex) => 
                                { 
                                    Message = ex.Message;
                                    Debug.WriteLine("OnError: Executing 1st on Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                                    Thread.Sleep(2000); 
                                },
                        () => { 
                                Message = "Completed";
                                Debug.WriteLine("Completed: Executing 1st on Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                                Thread.Sleep(2000);
                              });            
    }

    #endregion Operation Command
}
You can see that we have used an instance of RelayCommand for OperationCommand. Yes, this is the same RelayCommand which is from Josh Smith's MVVM article. Since we want the button always to be enabled so CanStartOperation always returns true. We have used StartOperation as Execute method for OperationCommand.

http://msdn.microsoft.com/en-us/magazine/dd419663.aspx

The following marble diagram might be used to represent the behavior of Fork.Join when all asynchronous operations actually return data. All this data is combined to generate a single OnNext with combined data. Since there is no exception so OnCompleted is generated when all data streams are completed.


Can Only Observable.Start be used?
In the above example we have used Observable.Start. We can use any IObservable no matter how it is created. We can even use IObservable (s) resulting from Observable.ToAsync from methods we want to execute asynchronously.
Observable.ForkJoin(
    Observable.Start(() => { 
                               Message = "In 1st Observable.Start";
                               Debug.WriteLine("Executing 1st on Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                               Thread.Sleep(2000);
                           }),
    Observable.Start(() => { 
                               Message = "In 2nd Observable.Start";
                               Debug.WriteLine("Executing 2nd on Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                               Thread.Sleep(2000);
                           }),
    Observable.ToAsync(myMethod)()
    )
    .Subscribe(
                (result) => { 
                                Message = result.ToString();
                                Debug.WriteLine("OnNext: Executing 1st on Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                                Thread.Sleep(2000); 
                            },
                (ex) => 
                        { 
                            Message = ex.Message;
                            Debug.WriteLine("OnError: Executing 1st on Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                            Thread.Sleep(2000); 
                        },
                () => { 
                        Message = "Completed";
                        Debug.WriteLine("Completed: Executing 1st on Thread: {0}", Thread.CurrentThread.ManagedThreadId);
                        Thread.Sleep(2000);
                      });            

Observable.ForkJoin and Exception Handling:
If any of the IObservable results in an exception the no OnNext message is generated from the resulting IObservable but a single OnError is generated. We can show this on a marble diagram as follows:


Operations returning different Data:
For Observable.ForkJoin, we can combine IObservable(s) which return no data or same / different data. Yes, it is possible that we have IObservable resulting in different data. We can use a different Overload of Observable.ForkJoin for this.
public void StartOperation()
{
    Observable.ForkJoin<int, string, string>(
        Observable.Start<int>(() =>
            {
                Thread.Sleep(2000);
                return 1;
            }),
        Observable.ToAsync<string>(myMethod)(),
        (StudentId, StudentName) => { return string.Format("Student- Id: {0}, Name: {1}", StudentId, StudentName); }
    ).Subscribe(
            (result) => { Message = result; },
            (ex) => { Message = ex.Message; });
}

private string myMethod()
{
    Thread.Sleep(5000);
    return "Muhammad";
}
When we run the application and click StartOperation. After some delay(simulated operational delay in parallel streams using Thread.Sleep) the window is updated. We can also use IObservables directly created using Observable.Create() method
public void StartOperation()
{
    Observable.ForkJoin<int, string, string>(
        Observable.Create<int>(
            (o) =>
            {
                Thread.Sleep(2000);
                o.OnNext(1);
                o.OnCompleted();

                return () => { };
            }),
            Observable.CreateWithDisposable<string>(
            (o) =>
            {
                Thread.Sleep(2000);
                o.OnNext("Muhammad");
                o.OnCompleted();

                return Disposable.Empty;
            }),
            (StudentId, StudentName) => { return string.Format("Student- Id: {0}, Name: {1}", StudentId, StudentName); }
    ).Subscribe(
            (result) => { Message = result; },
            (ex) => { Message = ex.Message; });

}
Let's run this. When we click the button the view updates as follows:


Many OnNext messages on Individual IObservable (s)
Observable.ForkJoin combines the last values of each Observable stream, combines them and generates OnNext message on the resulting IObservable.
public void StartOperation()
{
    Observable.ForkJoin<int, string, string>(
        Observable.Create<int>(
            (o) =>
            {
                Thread.Sleep(2000);
                o.OnNext(1);
                o.OnNext(2);
                o.OnCompleted();

                return () => { };
            }),
            Observable.Create<string>(
            (o) =>
            {
                Thread.Sleep(2000);
                o.OnNext("Muhammad");
                o.OnCompleted();

                return () => { };
            }),
            (StudentId, StudentName) => { return string.Format("Student- Id: {0}, Name: {1}", StudentId, StudentName); }
    ).Subscribe(
            (result) => { Message = result; },
            (ex) => { Message = ex.Message; });

}
When we run this, the first IObservable places two OnNext with data 1 and 2 sequentially. The second IObservable results in data "Muhammad". Let's run this:


It is because the third argument from this overload of Observable.ForkJoin has been used as a selector function. It has combined StudentId (int) and StudentName (string) into a string and placed OnNext on the resulting Observable.ForkJoin IObservable. When OnNext is received from the resulting IObservable, it has updated the Message property with the same message. Since this is bound to the view using WPF Binding System, the view is updated with this message.

Cleanup after Parallel Operations:
If we need to do some cleanup after these parallel operations are completed then we can do that in the Finally block executed after IObservable from Observable.ForkJoin finishes. As we know this gets executed no matter if these parallel operations were successful resulting in OnCompleted or there was some exception from any of the operations. In the latter case this gets executed after OnError is executed.

Observable.ForkJoin and Thread Management:
All the IObservable (s) in ForkJoin would be executing on different ThreadPool threads. The resulting IObservable would also be running on a TheredPool thread. Since ThreadPool threads might be recycled, it is possible that the same thread seems to be used for OnNext and OnCompleted as one of the threads used for executing one of the IObservable code. It must be remembered that OnNext, OnCompleted will always be executing on the same thread.
public void StartOperation()
{
    Message = "Operation running";

    Observable.ForkJoin(
        Observable.Start(() =>
        {
            Message = "In 1st Observable.Start";
            Debug.WriteLine("Executing 1st on Thread: {0}, IsThreadPoolThread: {1} ", 
                Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(2000);
        }),
        Observable.Start(() =>
        {
            Message = "In 2nd Observable.Start";
            Debug.WriteLine("Executing 2nd on Thread: {0}, IsThreadPoolThread: {1}",
                Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(2000);
        }),                
        Observable.Start(() => 
        { 
            Message = "In 3rd Observable.Start";
            Debug.WriteLine("Executing 3rd on Thread: {0}, IsThreadPoolThread: {1}", 
                Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
            Thread.Sleep(2000);                                           
        }))
        .Subscribe(
                    (result) =>
                    {
                        Message = result.ToString();
                        Debug.WriteLine("OnNext: Executing on Thread: {0}, IsThreadPoolThread: {1}", 
                            Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
                        Thread.Sleep(2000);
                    },
                    (ex) =>
                    {
                        Message = ex.Message;
                        Debug.WriteLine("OnError: Executing on Thread: {0}, IsThreadPoolThread: {1}", 
                            Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
                        Thread.Sleep(2000);
                    },
                    () =>
                    {
                        Message = "Completed";
                        Debug.WriteLine("Completed: Executing on Thread: {0}, IsThreadPoolThread: {1}", 
                            Thread.CurrentThread.ManagedThreadId, Thread.CurrentThread.IsThreadPoolThread);
                        Thread.Sleep(2000);
                    });
}

Executing 1st on Thread: 3, IsThreadPoolThread: True
Executing 2nd on Thread: 12, IsThreadPoolThread: True
Executing 3rd on Thread: 11, IsThreadPoolThread: True
OnNext: Executing on Thread: 11, IsThreadPoolThread: True
Completed: Executing on Thread: 11, IsThreadPoolThread: True

Executing 1st on Thread: 11, IsThreadPoolThread: True
Executing 2nd on Thread: 10, IsThreadPoolThread: True
Executing 3rd on Thread: 12, IsThreadPoolThread: True
OnNext: Executing on Thread: 12, IsThreadPoolThread: True
Completed: Executing on Thread: 12, IsThreadPoolThread: True

Executing 1st on Thread: 11, IsThreadPoolThread: True
Executing 2nd on Thread: 10, IsThreadPoolThread: True
Executing 3rd on Thread: 12, IsThreadPoolThread: True
OnNext: Executing on Thread: 3, IsThreadPoolThread: True
Completed: Executing on Thread: 3, IsThreadPoolThread: True


Download Code: