Friday, December 23, 2011

WPF 4.5 - Accessing DataBound Collections on Non-UI Thread

WPF has ItemsControl to show a collection of items. In MVVM, ItemsControl is data-bound with a collection in the view model. These collections might take a long time to load when the form is being shown. They might be constantly updated throughout the life cycle of the view. If we do it in the main application thread then it might cost the responsiveness of the application. Hence the need for a background thread for these operations. Well, the world has not been so simple.


As we know that the UI elements have affinity to the UI thread in WPF. It also does not allow playing with the elements collection bound as DataSource on any thread other than UI thread. And believe me, this really hurts !!! All we had were a few workarounds but no real solution. With WPF 4.5 Developer's preview, the situation improves a little. It is a step forward in the direction for providing these updates in some other thread. Although I do think that the way it is provided could be a little better than that but whatever makes my collection available to a non-UI thread. I don't really mind.

Let's understand this neat feature by creating a simple example. Let's have a simple view with a ListBox. The ListBox is supposed to display the history of signals received from a central server.


We can design the above view in XAML as follows:
<Window x:Class="MVVMCollectionNonUIThread.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:MVVMCollectionNonUIThread"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="30" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <Border Background="Navy" Grid.Row="0">
            <TextBlock Text="WPF 4.5 - Collections Access Across Threads" FontSize="20" 
                       Foreground="White" FontWeight="Bold"
                       TextAlignment="Center" VerticalAlignment="Center" />
        </Border>
        <ListBox Margin="3,5,3,5" Grid.Row="1" ItemsSource="{Binding RandomList}"  />
    </Grid>
</Window>
The above view has MainWindowViewModel set as the DataContext. It expects the DataContext to have a collection, named RandomList. This collection is data-bound to the ListBox so it should have the history of instances when the signal is received from the server. Now let's start defining the view model as per expectation.
namespace MVVMCollectionNonUIThread
{
    using System.Collections.ObjectModel;
    using System.Timers;
    using System.Windows.Data;

    class MainWindowViewModel
    {
        Timer _t1;

        ObservableCollection<string> _randomList;
        public ObservableCollection<string> RandomList
        {
            get
            {
                if (_randomList == null)
                {
                    _randomList = new ObservableCollection<string>();
                }

                return _randomList;
            }
        }

        public MainWindowViewModel()
        {
            _t1 = new Timer(300);
            _t1.Elapsed += new System.Timers.ElapsedEventHandler(_t1_Elapsed);
            _t1.Start();
        }

        void _t1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            RandomList.Add(string.Format("Signal Time : {0}", e.SignalTime));
        }

    }
}
In order to simulate the signal reception, we have used System.Timers.Timer. The timer would tick after at least 300 ms. This event is handled by _t1_Elapsed. We are just adding an item to RandomList each time the timer ticks. This event handler is to simulate the signal received from the server. Generally, this client / server communication is handled on a different thread like this handler. Since we are following through this post, if we run the application this results in the EXPECTED exception when the item is being added to RandomList in _t1_Elapsed (non-UI thread) [This is generally UNEXPECTED and comes as a surprise if developer doesn't know about it yet.]


FYI: In Winform, we can cause Elapsed event for System.Timers.Timer to be raised in UI thread by setting the SyncrhnizingObject property. We have discussed about this in our timers discussion [http://shujaatsiddiqi.blogspot.com/2010/10/timers-for-net-applications.html]

WPF 4.5 Developer's preview has provided certain new static methods in BindingOperations class to fix this behavior. The list of new methods I could find is as follows:
  1. AccessCollection
  2. DisableCollectionSynchronization
  3. EnableCollectionSynchronization
This also have some overloads. Let's see how we can fix our little example with these methods. We really can go around by just using EnableCollectionSynchronization. It is to report a collection to be accessible in non-UI threads. In order to provide thread synchronization, we need to provide the synchronization mechanism. Simply we can use the overload which needs lock object. Let's update the view model as follows:
namespace MVVMCollectionNonUIThread
{
    using System.Collections.ObjectModel;
    using System.Timers;
    using System.Windows.Data;

    class MainWindowViewModel
    {
        Timer _t1;
        object _lockObj = new object();

        ObservableCollection<string> _randomList;
        public ObservableCollection<string> RandomList
        {
            get
            {
                if (_randomList == null)
                {
                    _randomList = new ObservableCollection<string>();
                }

                return _randomList;
            }
        }

        public MainWindowViewModel()
        {
             BindingOperations.EnableCollectionSynchronization(RandomList, _lockObj);

            _t1 = new Timer(300);
            _t1.Elapsed += new System.Timers.ElapsedEventHandler(_t1_Elapsed);
            _t1.Start();

            
        }

        void _t1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            RandomList.Add(string.Format("Signal Time : {0}", e.SignalTime));
        }

    }
}
Here we just have added BindingOperations.EnableCollectionSynchronization to the view model's contructor for the RandomList collection. We have used the instance member _lockObj as the lock object. That's it! Let's run this now!


Just one thing. The feature is available through BindingOperations available in PresentationFramework assembly. Some developers like to keep their view models in a separate project and they don't like referencing this assembly in that project.


Download:

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:

Sunday, August 14, 2011

Silverlight 5 Beta - Relative Source Binding

In this post we will be discussing another new feature of Silverlight 5 Beta. It is Relative Source binding. RelativeSource has long been missing from Silverlight. It has always been there in WPF. Silverlight 5 is currently available in Beta and can be downloaded from here:

http://www.microsoft.com/download/en/details.aspx?id=23887

Let's create a MVVM Light Silverlight application AppSilverlightRelativeSourceBinding. It would have a list of students on display. The user should be allowed to remove any student on the list. In order to see the application of Relative Source binding, we would see how we can bind the Command on the child element to a parent element. Actually, the Remove button on child view should be bound to a Command in the DataContext of a parent element in the hierarchy [UserControl].


Just make sure that you have Silverlight 5 version selected in the project's properties.


This view model is the Main view model of the application. It has a collection of students (StudentViewModel). Since the collection is an ObservableCollection, all the addition / removal of elements in the collection would directly reflected in the view. It also has a Command which removes the student from the collection. This is the Command which would be bound by child elements.
namespace AppSilverlightRelativeSourceBinding.ViewModel
{
    using GalaSoft.MvvmLight;
    using System.Collections.ObjectModel;
    using GalaSoft.MvvmLight.Command;

    public class MainViewModel : ViewModelBase
    {
        #region Properties

        public string Welcome
        {
            get
            {
                return "Silverlight 5 Beta - Relative Source Binding";
            }
        }

        ObservableCollection<StudentViewModel> _students;
        public ObservableCollection<StudentViewModel> Students
        {
            get
            {
                if (_students == null)
                {
                    _students = new ObservableCollection<StudentViewModel>();

                    _students.Add(new StudentViewModel() { StudentFirstName = "Kamran", StudentLastName = "Khan" });
                    _students.Add(new StudentViewModel() { StudentFirstName = "Asad", StudentLastName = "Hussain" });
                    _students.Add(new StudentViewModel() { StudentFirstName = "Faisal", StudentLastName = "Lashari" });
                    _students.Add(new StudentViewModel() { StudentFirstName = "Hyder", StudentLastName = "Baloch" });
                    _students.Add(new StudentViewModel() { StudentFirstName = "Baber", StudentLastName = "Chaudhari" });
                }
                return _students;
            }
        }

        #endregion

        #region Commands

        RelayCommand<StudentViewModel> _removeStudentCommand;
        public RelayCommand<StudentViewModel> RemoveStudentCommand
        {
            get
            {
                return _removeStudentCommand ??
                        new RelayCommand<StudentViewModel>((student) =>
                        {
                            if (this.Students.Contains(student))
                            {
                                this.Students.Remove(student);
                            }
                        });
            }
        }

        #endregion        
    }
}

The definition of StudentViewModel used above is as follows:
namespace AppSilverlightRelativeSourceBinding.ViewModel
{   
    using GalaSoft.MvvmLight;

    public class StudentViewModel : ViewModelBase
    {
        #region Notifiable Properties

        string _studentLastName;
        public string StudentLastName
        {
            get { return _studentLastName; }
            set
            {
                _studentLastName = value;
                RaisePropertyChanged("StudentLastName");
            }
        }

        string _studentFirstName;
        public string StudentFirstName
        {
            get { return _studentFirstName; }
            set
            {
                _studentFirstName = value;
                RaisePropertyChanged("StudentFirstName");
            }
        }

        #endregion

    }
}
It simply has two properties for first and last names of a student. The view model inherits from ViewModelBase which is provided by MVVM Light toolkit. Now let's see how we can display this view model. It is an implicit DataTemplate to show the student. The first and last names are displayed in a TextBlock. It also has a Remove button. Clicking the button would delete the student from the collection. Since StudentViewModel has no idea about which collection it has been part of and it has to be handled by something which holds this collection. So the button's Command needs to be bound to MainViewModel. This is why Relative Source binding makes most sense to be used here. Let's define this DataTemplate in MainSkin.xaml resource dictionary provided by MVVM Light.
<DataTemplate DataType="vm:StudentViewModel" >
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="30" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>
        <Button Content="Remove" Grid.Column="0"                       
                CommandParameter="{Binding}" >                
            <Button.Command>
                <Binding RelativeSource="{RelativeSource AncestorType=UserControl}" 
                         Path="DataContext.RemoveStudentCommand" />
            </Button.Command>
        </Button>
        <Border Grid.Column="1" />
        <Grid Grid.Column="2" >
            <TextBlock>  
                <Run Text="{Binding StudentLastName}" FontWeight="Bold" />
                <Run>
                    <Run.Text>
                        <Binding Path="StudentFirstName" StringFormat=",{0}" />
                    </Run.Text>
                    </Run>
            </TextBlock>
        </Grid>
    </Grid>
</DataTemplate>
We need to include this namespace in the above resource dictionary.
xmlns:vm="clr-namespace:AppSilverlightRelativeSourceBinding.ViewModel"
Now the design of MainPage is simple enough. Mainly it has a ListBox to display the collection of StudentViewModel. Since MainSkin.xaml resource dictionary is merged here, the implicit DataTemplate is automatically applied.
<UserControl x:Class="AppSilverlightRelativeSourceBinding.MainPage"
             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"
             mc:Ignorable="d"            
             DataContext="{Binding Main, Source={StaticResource Locator}}">
    <UserControl.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="Skins/MainSkin.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot">
        <Grid.RowDefinitions>
            <RowDefinition Height="auto" />
            <RowDefinition Height="*" />
        </Grid.RowDefinitions>
        <TextBlock FontSize="36" Grid.Row="0"
                   FontWeight="Bold"
                   Foreground="Purple"
                   Text="{Binding Welcome}"
                   VerticalAlignment="Center"
                   HorizontalAlignment="Center"
                   TextWrapping="Wrap" />
        <ListBox ItemsSource="{Binding Students}"
                 Grid.Row="1" />
    </Grid>
</UserControl>
When we run the application, the application is loaded as follows:


Download Code:

Friday, August 12, 2011

Silverlight 5 Beta - Binding Style's Setter.Value

In this post we will be discussing a binding enhancements in Silverlight 5. Now Style's Setters also support binding for their Value property. Silverlight 5 is currently available in Beta and can be downloaded from here:

http://www.microsoft.com/download/en/details.aspx?id=23887

Let's consider a simple example in which we need to define an application banner in a TextBlock. The application banner will provided by the view model so it needs to be bound to the TextBlock's Text property using Binding extension.


Let's consider a simple example in which we need to define an application banner in a TextBlock. The application banner will provided by the view model so it needs to be bound to the TextBlock's Text property using Binding extension. Let's update the MainPage as follows:
<UserControl x:Class="AppSilverlightBindingInStyle.MainPage"
        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:local="clr-namespace:AppSilverlightBindingInStyle"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400">
    <UserControl.DataContext>
        <local:MainViewModel BannerText ="Application Banner" />
    </UserControl.DataContext>
    <UserControl.Resources>
        <Style TargetType="TextBlock" >            
            <Setter Property="Text" Value="{Binding BannerText}" />
            <Setter Property="FontSize" Value="30" />           
        </Style>
    </UserControl.Resources>
    <Grid x:Name="LayoutRoot" Background="White">
        <TextBlock Name="bannerBox" TextAlignment="Center" />
    </Grid>
</UserControl>
It has a simple TextBlock in the view. The DataContext is specified as MainViewModel. It has an inline assignment to its BannerText property. In the Resources we have a Style defined for the TextBlock. This would serve as the default Style of any TextBlock in the page unless overriden. Look at how we are able to bind the Value property of Style's Setter.

The view model just needs to have a property BannerText. The definition of MainViewModel used as DataContext in the above view is as follows:
namespace AppSilverlightBindingInStyle
{
    using System.ComponentModel;

    public class MainViewModel : INotifyPropertyChanged
    {
        #region Properties

        string _bannerText;
        public string BannerText
        {
            get { return _bannerText; }
            set
            {
                _bannerText = value;
                OnPropertyChanged("BannerText");
            }
        }

        #endregion
        
        #region INotifyPropertyChanged implementation

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

        #endregion        
    }
}
When we run the application, it is shown as follows:


Download Code:


Monday, August 8, 2011

Implicit DataTempates in Silverlight 5 Beta

In this post we are going to discuss a new feature expected to be released in Silverlight 5. This feature is implicit DataTemplates. Those who come from WPF background to Silverlight often find it difficult to design without implicit DataTemplates. Well, this limitation has been worked in Silverlight 5 and it is available in the beta release. Silverlight 5 beta tools can be downloaded from here:

http://www.microsoft.com/download/en/details.aspx?id=23887

Let's create a sample Silverlight application and name it AppSilverlightImplicitDataTemplates.


Make sure that you have Silverlight 5 option selected in the following screen displayed right after the previous one.


You would need a reference of System.Windows.Controls.Data.Input assembly for Labels. If you directly drag and drop the Label Control from Toolbox on the designer surface, the assembly is automatically referenced.


Let's suppose we have the following view model. It has a collection of students. We want the user to select a particular student and allow that to be edited.
namespace AppSilverlightImplicitDataTemplates
{
    using System.Collections.ObjectModel;
    using System.Collections.Generic;

    public class MainViewModel : ViewModelBase
    {
        ObservableCollection<StudentViewModel> _students;
        public  ObservableCollection<StudentViewModel> Students
        {
            get
            {
                if (_students == null)
                {
                    _students = new ObservableCollection<StudentViewModel>();
                    _students.Add(new StudentViewModel() { StudentFirstName = "Muhammad", StudentLastName = "Siddiqi" });
                    _students.Add(new StudentViewModel() { StudentFirstName = "Jayson", StudentLastName = "Abante" });
                    _students.Add(new StudentViewModel() { StudentFirstName = "Meena", StudentLastName = "Gulla" });                                        
                }
                return _students;
            }
        }
    }
}
The view model is inheriting from ViewModelBase class. It is basically for providing general functionality to all view models specially implementation of INotifyPropertyChanged interface. As you might have guessed, like this view model, all others view models in the application would also be inheriting from this.
namespace AppSilverlightImplicitDataTemplates
{
    using System.ComponentModel;

    public class ViewModelBase : INotifyPropertyChanged
    {
        #region INotifyPropertyChanged Implementation

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

        #endregion

    }
}
In MainViewModel we have used StudentViewModel collection. It basically has two properties StudentFirstName and StudentLastName. Its definition can be as follows:
namespace AppSilverlightImplicitDataTemplates
{
    using System.ComponentModel;

    public class StudentViewModel : ViewModelBase
    {
        #region Notifiable Properties

        string _studentLastName;
        public string StudentLastName
        {
            get { return _studentLastName; }
            set
            {
                _studentLastName = value;
                OnPropertyChanged("StudentLastName");
            }
        }

        string _studentFirstName;
        public string StudentFirstName
        {
            get { return _studentFirstName; }
            set
            {
                _studentFirstName = value;
                OnPropertyChanged("StudentFirstName");
            }
        }

        #endregion

    }
}
As you can see above, it also inherits from ViewModelBase. The two properties support change notification by calling OnPropertyChanged method. In turn this would raise PropertyChanged event. As we have discussed already that we would be needing to use this view model in two different types of views. One is just for display for selection based control used to display the collection of students. We also need a different view to allow a student to be edited.

For displaying in collection based control:
<UserControl x:Class="AppSilverlightImplicitDataTemplates.StudentDisplayView"
        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"
        mc:Ignorable="d" >    
    <TextBlock>
        <Run Text="{Binding StudentLastName}" FontWeight="Bold" />
        <Run Text="," />
        <Run Text="{Binding StudentFirstName}" />
    </TextBlock>
</UserControl>

For editing StudentViewModel:
<UserControl x:Class="AppSilverlightImplicitDataTemplates.StudentEditView"
        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"    
        mc:Ignorable="d"
        xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk" >
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="93" />
            <ColumnDefinition Width="307" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>           
            <RowDefinition Height="35" />
            <RowDefinition Height="*" />            
        </Grid.RowDefinitions>     
        <sdk:Label Height="23" HorizontalAlignment="Left"
                   Margin="12,12,0,0"  VerticalAlignment="Top"                    
                   Content="First Name" Width="83" Grid.ColumnSpan="2" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="8,8,0,0" 
                 VerticalAlignment="Top" Width="287" Text="{Binding StudentFirstName}" Grid.Column="1" />
        <sdk:Label Content="Last Name" Height="23" HorizontalAlignment="Left" 
                   Margin="12,7,0,0" VerticalAlignment="Top" Width="83" Grid.Row="1" Grid.ColumnSpan="2" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="8,3,0,0" 
                 VerticalAlignment="Top" Width="287" Grid.Row="1" 
                 Text="{Binding StudentLastName}" Grid.Column="1" />
    </Grid>
</UserControl>

Using UserControls in DataTemplate
By default we need the StudentViewModel type of objects to be using the display one. So we can define it as application resource. Just updated App.xaml as follows:
<Application xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
             x:Class="AppSilverlightImplicitDataTemplates.App"
             xmlns:local="clr-namespace:AppSilverlightImplicitDataTemplates"
             >
    <Application.Resources>
        <DataTemplate DataType="local:StudentViewModel">
            <local:StudentDisplayView />
        </DataTemplate>
    </Application.Resources>
</Application>
Now we define the Main application view. As we have discussed, we need to provide a collection of Students and allow the user to select any one of them and edit that.
<UserControl x:Class="AppSilverlightImplicitDataTemplates.MainPage"
        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:local="clr-namespace:AppSilverlightImplicitDataTemplates"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400"
        xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
    <UserControl.DataContext>
        <local:MainViewModel />
    </UserControl.DataContext>    
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="97*" />
            <ColumnDefinition Width="303*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="43*" />
            <RowDefinition Height="257*" />
        </Grid.RowDefinitions>
        <sdk:Label Height="22" HorizontalAlignment="Left" Margin="11,18,0,0"
                   Name="label1" VerticalAlignment="Top" Width="86"
                   Content="Select Student" DataContext="{Binding Path=Students}" />
        <ComboBox Height="24" HorizontalAlignment="Left" Margin="6,14,0,0"
                  Name="cmbStudents" VerticalAlignment="Top" Width="285"
                  ItemsSource="{Binding Students}" Grid.Column="1" />
        <ContentControl 
            DataContext="{Binding ElementName=cmbStudents, Path=SelectedItem}" 
            Content="{Binding}" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" 
            Margin="11,18,0,0"/>
    </Grid>
</UserControl>
Now lets run the application. It appears as follows:


Now select a student from the combo box. The same student is loaded in the ContentControl as follows:


Now we need the ContentControl to be using the editing type of UserControl for StudentViewModel so that it could be edited. Let's override it as follows in the main view:
<UserControl x:Class="AppSilverlightImplicitDataTemplates.MainPage"
        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:local="clr-namespace:AppSilverlightImplicitDataTemplates"
        mc:Ignorable="d"
        d:DesignHeight="300" d:DesignWidth="400"
        xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
    <UserControl.DataContext>
        <local:MainViewModel />
    </UserControl.DataContext>    
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="97*" />
            <ColumnDefinition Width="303*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="43*" />
            <RowDefinition Height="257*" />
        </Grid.RowDefinitions>
        <sdk:Label Height="22" HorizontalAlignment="Left" Margin="11,18,0,0"
                   Name="label1" VerticalAlignment="Top" Width="86"
                   Content="Select Student" DataContext="{Binding Path=Students}" />
        <ComboBox Height="24" HorizontalAlignment="Left" Margin="6,14,0,0"
                  Name="cmbStudents" VerticalAlignment="Top" Width="285"
                  ItemsSource="{Binding Students}" Grid.Column="1" />
        <StackPanel Margin="11,18,0,0" Grid.Row="1" 
                    Grid.Column="0" Grid.ColumnSpan="2" >
            <StackPanel.Resources>
                <DataTemplate DataType="local:StudentViewModel" >
                    <local:StudentEditView />
                </DataTemplate>
            </StackPanel.Resources>
            <ContentControl 
            DataContext="{Binding ElementName=cmbStudents, Path=SelectedItem}" 
            Content="{Binding}" 
            />
        </StackPanel>
    </Grid>
</UserControl>
Here we have thrown the ContentControl inside a StackPanel. In the Resources section of the StackPanel, we have overridden the DataTemplate for StudentViewModel. Since local resource have preference over application level resources so this DataTemplate is applied for the StudentViewModel in ContentControl. When we run the application and select a student, the instance is loaded in the ContentControl with correct DataTemplate applied.


Download:

Sunday, August 7, 2011

Binding Debugging in Silverlight 5

In this post we will be discussing a long desired feature in XAML based applications. This feature is Binding Debugging specified in XAML. This feature is introduced in Silverlight 5.

Let's create a sample Silverlight application AppSilverlightDebuggingDemo.


Definitely an installation of Silverlight 5 is required for this example. Silverlight 5 beta tools can be downloaded from here:

http://www.microsoft.com/download/en/details.aspx?id=23887

If you have it installed already, the second step would allow you to select Silverlight 5 as the Silverlight version.


Here in order to test our example we are selecting the option to create a new website to host the silvelight application specified in previous step. When you hit OK the two projects should be available in Solution Explorer as follows:


Now we add a view model to the Silverlight project MainPageViewModel. It is a simple view model implementing INotifyPropertyChanged interface for supporting change notification for its properties. The view model has two properties StudentId and StudentName, setting both would cause PropertyChanged event to be triggered.
namespace AppSilverlightDebuggingDemo
{
    using System.ComponentModel;

    public class MainPageViewModel : INotifyPropertyChanged
    {
        #region Notifiable Properties

        string _studentId;
        public string StudentId
        {
            get { return _studentId; }
            set
            {
                _studentId = value;
                OnPropertyChanged("StudentId");
            }
        }

        string _studentName;
        public string StudentName
        {
            get { return _studentName; }
            set
            {
                _studentName = value;
                OnPropertyChanged("StudentName");
            }
        }

        #endregion

        #region INotifyPropertyChanged Implementation

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

        #endregion        
    }
}

Let us update the definition of MainPage.xaml as follows:

<UserControl x:Class="AppSilverlightDebuggingDemo.MainPage"
    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:local="clr-namespace:AppSilverlightDebuggingDemo"             
    mc:Ignorable="d"
    d:DesignHeight="300" d:DesignWidth="400" 
    xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">
    <UserControl.DataContext>
        <local:MainPageViewModel StudentId="1" StudentName="Muhammad" />
    </UserControl.DataContext>
    <Grid x:Name="LayoutRoot" Background="White">
        <Grid.RowDefinitions>
            <RowDefinition Height="48*" />
            <RowDefinition Height="35*" />
            <RowDefinition Height="36*" />
            <RowDefinition Height="181*" />
        </Grid.RowDefinitions>
        <sdk:Label Height="24" HorizontalAlignment="Center" 
                   VerticalAlignment="Center" Width="189" FontWeight="Bold" FontSize="16"
                   Content="Student Information" Margin="106,24,106,0" />
        <sdk:Label Height="23" HorizontalAlignment="Left"
                   Margin="12,12,0,0" Name="lblStudentId" VerticalAlignment="Top"                    
                   Content="Student Id" Width="83" Grid.Row="1" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="101,8,0,0" 
                 VerticalAlignment="Top" Width="287" Grid.Row="1"
                 Text="{Binding StudentId}" />
        <sdk:Label Content="Student Name" Height="23" HorizontalAlignment="Left" 
                   Margin="12,8,0,0" VerticalAlignment="Top" Width="83" Grid.Row="2" />
        <TextBox Height="23" HorizontalAlignment="Left" Margin="101,4,0,0" 
                 VerticalAlignment="Top" Width="287" Grid.Row="2" 
                 Text="{Binding StudentName}"/>        
    </Grid>
</UserControl>
In the above view we are using the view model defined previously as DataContext. Here we have assigned some default values the two properties so that the view is loaded with some already existing information. We are binding the properties StudentId and StudentName to the two TextBox(es).Now when we run the application, it should display as follows:


Now open the view's XAML and try hitting F9 while putting the cursor on each of the bindings. This would insert a break point in the Binding expression. The execution would break at these bindings like a regular break point but the difference is that now this break point has been inserted in XAML.


Now let us run the application again. The execution would step at the break point as follows:


It not only steps at the breakpoint, it also lets us to use regular debugging tools provided in Visual Studio. You can see that we have the Locals window opened and it is showing the values of the properties of the DataContext. It also lets us find the issues with binding. Let's update the StudentName binding as follows:


How easy do you think your life would be. Easy debugging...no late sittings at work...more time with family :)

Download Code:

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:

Monday, July 25, 2011

INotifyPropertyChanged and Magic Strings

One of the argument against INotifyPropertyChanged is the magic strings based notification. Although this is not as big an issue as many people think it is but I have seen people finding it difficult to explain to their fellow developers about this. As an alternate they make their View Models a DependencyObject and provide Dependency Properties for all properties that should be supporting change notifications.

In this post we are going to discuss how we can avoid the use of magic strings and still be able to use INotifyPropertyChanged. For those who needs some glimpse of the problem, INotifyPropertyChanged based properties appear something like this in general.
private string _firstName;
public string FirstName
{
    get { return _firstName; }
    set
    {
       _firstName = value;
       OnPropertyChanged("FirstName");
    }
}
And that is what we want to avoid. We don’t want an OnPropertyChanged with a magic string.

Let’s create a simple view with a simple TextBox for entering user information (First Name). In order to prove that the property change notifications are working, we add one TextBlock. This TextBlock is bound to the same property. This is a OneWay binding which is one-way from Source to Target property. We have set the UpdateSourceTrigger on TextBox’s binding to PropertyChanged so that we don’t have to lose focus from the TextBox in order to trigger the copying of text to the view model’s property.
<Window x:Class="WpfApp_INotifyWithoutMagicString.MainWindow"
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
       xmlns:local="clr-namespace:WpfApp_INotifyWithoutMagicString"
       Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
       <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
       <Label Content="First Name" Height="28" HorizontalAlignment="Left"
              Margin="22,54,0,0" Name="label1" VerticalAlignment="Top" Width="80" />
       <TextBox Height="28" HorizontalAlignment="Left" Margin="108,54,0,0"
                Name="textBox1" VerticalAlignment="Top" Width="356"
                Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged}" />
       <TextBlock Height="121" HorizontalAlignment="Left" Margin="108,101,0,0"
                  Name="textBlock1" Text="{Binding FirstName, UpdateSourceTrigger=PropertyChanged, Mode=OneWay}"
                  Background ="Thistle" VerticalAlignment="Top" Width="356" />        
   </Grid>
</Window>
We are instantiating MainWindowViewModel and using it as DataContext of the Window. The view model is assumed to have a property, named FirstName. You can find the definition of MainWindowViewModel as follows:
&class MainWindowViewModel : BaseViewModel<MainWindowViewModel>
{
    private string _firstName;
    public string FirstName
    {
       get { return _firstName; }
       set
       {
           _firstName = value;
           OnPropertyChanged(viewModel => viewModel.FirstName);
       }
    }
}
As expected, the above view model has a public property FirstName. The difference is how we have called OnPropertyChanged. As we mentioned in the start of this post, there is no magic string. The definition of OnPropertyChanged is inherited from ViewModelBase. But one thing is apparent, the definition of the method should be dealing with the handling of the lambda expression provided as method argument.
class MainWindowViewModel : ViewModelBase<MainWindowViewModel>
{
    private string _firstName;
    public string FirstName
    {
       get { return _firstName; }
       set
       {
           _firstName = value;
           OnPropertyChanged(viewModel => viewModel.FirstName);
       }
    }
}
The definition of ViewModelBase is as follows:
class ViewModelBase<T> : INotifyPropertyChanged where T : class
{
    #region Implementation INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    protected void OnPropertyChanged(Expression<Func<T, object>> expression)
    {
       if (expression == null || !(expression.Body is MemberExpression))
       {
           return;
       }

       PropertyChanged(this, new PropertyChangedEventArgs(((MemberExpression)expression.Body).Member.Name));
    }

    #endregion Implementation INotifyPropertyChanged
}
ViewModelBase is implemented as generic type. This is to allow the user to avoid casting. The other implementation might have been as follows:
class ViewModelBase : INotifyPropertyChanged
{
    #region Implementation INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    protected void OnPropertyChanged(Expression<Func<object, object>> expression)
    {
       if (expression == null || !(expression.Body is MemberExpression))
       {
           return;
       }

       PropertyChanged(this, new PropertyChangedEventArgs(((MemberExpression)expression.Body).Member.Name));
    }

    #endregion Implementation INotifyPropertyChanged
}
But since this is based on object type of argument for lambda expression. In order to access the FirstName property from the argument, the developer need to typecast. Wrong typecasting might result in runtime exceptions if the object being type casted doesn’t have the property with same name.
public string FirstName
{
    get { return _firstName; }
    set
    {
       _firstName = value;
       OnPropertyChanged(viewModel => ((MainWindowViewModel)viewModel).FirstName);
    }
}
The developer might be just using the code similar to the following code. But this must be remembered that we are not passing the current instance of View Model. We are just passing the lambda expression as argument to OnPropertyChanged. Its evaluation would result in raising PropertyChanged event for the same property.
public string FirstName
{
    get { return _firstName; }
    set
    {
       _firstName = value;
       OnPropertyChanged(viewModel => FirstName);
    }
}
Which leads us to third implementation of ViewModelBase without even specifying the type of view model as the argument for lambda. I think this would be the simplest and easiest implementation of the Base View Model.
class ViewModelBase : INotifyPropertyChanged 
{
    #region Implementation INotifyPropertyChanged

    public event PropertyChangedEventHandler PropertyChanged = delegate { };

    protected void OnPropertyChanged(Expression<Func<object>> expression)
    {
       if (expression == null || !(expression.Body is MemberExpression))
       {
           return;
       }

       PropertyChanged(this, new PropertyChangedEventArgs(((MemberExpression)expression.Body).Member.Name));
    }

    #endregion Implementation INotifyPropertyChanged
}
If we implement our ViewModel as above then it might result in simplest OnPropertyChanged as follows:
public string FirstName
{
    get { return _firstName; }
    set
    {
       _firstName = value;
       OnPropertyChanged(() => FirstName);
    }
}
No matter what implementation of ViewModelBase you are using, when you would run the application and enter text in the TextBox, it would update the FirstName property in the DataContext (MainWindowViewModel’s instance). This is proved through the same data being displayed in the TextBlock below.

Saturday, April 23, 2011

Clicking away from FrameworkElement when mouse is still captured

This post is about a very specific problem about mouse capturing. There are certain situations in which we need to be notified when mouse is clicked outside the bounds of an element. As all of you know that this is classical mouse capturing situation used for various tasks including Drag & Drop. When we search around for a solution for this then we find out an attached event Mouse.PreviewMouseDownOutsideCapturedElement. This is documented in msdn as follows:

“Occurs when the primary mouse button is pressed outside the element that is capturing mouse events.”
<Window x:Class="WpfApplication3.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="483" Width="553"      
Mouse.PreviewMouseDownOutsideCapturedElement="Window_PreviewMouseDownOutsideCapturedElement" >
    <StackPanel>
        <StackPanel Height="33">
            <TextBox Name="textBox1" />
        </StackPanel>
        <StackPanel  >           
            <Button Content="Button" Height="32" HorizontalAlignment="Left"
                    Margin="126,209,0,0" Name="button1" VerticalAlignment="Top"
                    Width="297" Click="button1_Click" />
        </StackPanel>
    </StackPanel>
</Window>
This definitely does what it is supposed to do. In order to get this to work we must have a captured element. Let’s capture mouse on textBox1. So, clicking a mouse outside textBox1 (captured element) should result in causing this handler to get called.
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();       
    }

    private void Window_PreviewMouseDownOutsideCapturedElement(object sender, MouseButtonEventArgs e)
    {

    }

    private void button1_Click(object sender, RoutedEventArgs e)
    {
        Mouse.Capture(this.textBox1);
    }
}
Let’s run this. We have the display as presented in XAML. It has a TextBox and a Button. When we click the button textBox1 captures the mouse using static Capture method on Mouse. We have subscribed PreviewMouseDownOutsideCapturedElement event in XAML. We could have easily done that in code behind as well. Obviously we would need AddHandler… mechanism for registering with an attached event. This is similar to XAML attached properties. When implemented in WPF, they work as Dependency properties. Similarly Attached events from XAML are implemented as routed events in WPF.

Now the issue is that this event gets fired even when we click inside textBox1. This seems awkwardly strange as this is purely not expected behavior when we read the msdn description. Now we know the behavior. How can we fix this? We just need to find out where the mouse was clicked and we should be good to go. You might be wondering we can get around that we can do that either through the sender parameter or Source / OriginalSource from MouseButtonEventArgs. But the strange thing is that sender is always the element on which the event is registered. So if were registering it on textBox1, it would be textBox1. Currently this would always be the Window object no matter where we click on the Window after capturing the mouse by clicking the button. On top of that, Source and OriginalSource are always the captured element. The other properties which could inform us if the mouse is directly over the textBox1 are always true.

The only way to fix it seems to be to do it ourselves. We can find out the position of mouse. If the position of mouse is within the bounds of captured element then we can just ignore this. Otherwise, we can execute the same logic as we were supposed to execute. We might need to register the event again.

private void Window_PreviewMouseDownOutsideCapturedElement(object sender, MouseButtonEventArgs e)
{
    bool isClickedWithin =  IsMouseClickWithin(this.textBox1, e.MouseDevice.GetPosition(this.textBox1));

    if(isClickedWithin)
    {
        //execute some logic
    }
}

private bool IsMouseClickWithin(FrameworkElement element, Point point)
{
    return (element.ActualWidth > point.X && element.ActualHeight > point.Y) || point.X < 0 || point.Y < 0;
}
In the above example, it is checking if the mouse position is within the actual bounds of textBox1. IsMouseClickWithin returns true for this. It returns false otherwise.

Wednesday, April 13, 2011

Hosting SQL CE based Entity Models in WCF Data Service

While developing an application in ASP.net for my friend I realized that we can not SQL Compact Edition with ASP.net. When you try to do that you would get this error page.

SQL Compact Edition error when used with ASP.net
The server encountered an error processing the request. The exception message is 'SQL Server Compact is not intended for ASP.NET development.'. See server logs for more details. The exception stack trace is: 

at System.Data.SqlServerCe.SqlCeRestriction.CheckExplicitWebHosting() at System.Data.SqlServerCe.SqlCeConnection..ctor() at System.Data.SqlServerCe.SqlCeProviderFactory.CreateConnection() at System.Data.EntityClient.EntityConnection.GetStoreConnection(DbProviderFactory factory) at System.Data.EntityClient.EntityConnection.ChangeConnectionString(String newConnectionString) at System.Data.EntityClient.EntityConnection..ctor(String connectionString) at System.Data.Objects.ObjectContext.CreateEntityConnection(String connectionString) at System.Data.Objects.ObjectContext..ctor
I got this when I was hosting WCF DataService in the ASP.net application exposing my Entity Model. The entities were based on a SQL CE database. To see this message, we need to set the behavior of service to allow the exception details to be shown to the user by this setting on the WCF Data Service.
[ServiceBehavior(IncludeExceptionDetailInFaults = true)]
public class MyDataService : DataService<App.ModelEntities>
{
    ...
}
Otherwise we see the following message when we run the application:

Although this is more secure message as we are not showing the stack trace to the user but during development this message seems very irritating. In order to avoid this and to get the detailed message set the above specified Service Behavior for the WCF Data Service.

This must be remembered that this limitation seems more like a suggestion by Microsoft so as to discourage the use of SQL Server Compact Edition for public facing systems because of its security limitations. But there might be valid reasons to still use SQL CE for ASP.net applications for demo applications or in-house developed applications. In order to get around that we can use AppDomain slots to set SQLServerCompactEditionUnderWebHosting to true. This results in allowing the use of SQL Server Compact edition by the runtime. We can set that during application startup in Global.asax.
public class Global : System.Web.HttpApplication
{
    void Application_Start(object sender, EventArgs e)
    {
        // Code that runs on application startup
        AppDomain.CurrentDomain.SetData("SQLServerCompactEditionUnderWebHosting", true);
    }
}
Now when we run the application we can see the service successfully giving XML data. We have discussed about AppDomain slots here:

http://shujaatsiddiqi.blogspot.com/2011/01/in-this-post-we-will-discuss-named-slot.html