Saturday, September 18, 2010

Binding when DataContext with Explicit Interface Implementation (INotifyPropertyChanged)

In this article, we will discuss how to support change notification using INotifyPropertyChanged when your DataContext explicitly implements some interface. You might want to bind some of the explicitly implemented property to your View.

Lets consider this interface. This is defining a contract of having a string property, named Name. Both get and set are part of the interface contract.

public interface IWindow1ViewModel
{
string Name { get; set; }
}

Now we implement this interface in class Window1ViewModel. This class explicitly implements this interface. The interesting thing is that this class should also support change notification of its properties, so it implements INotifyPropertyChanged. Look at setter of Name property. You can see that in order to support change notification with INotifyPropertyChanged, we don't need to generate notification with the name of interface and just the name of property should work.

public class Window1ViewModel : INotifyPropertyChanged, IWindow1ViewModel
{
#region IWindow1ViewModel Members

string _name;
string IWindow1ViewModel.Name
{
get
{
return _name;
}
set
{
_name = value;
onPropertyChanged("Name");
}
}
#endregion

#region INotifyPropertyChanged Members

public event PropertyChangedEventHandler PropertyChanged;

private void onPropertyChanged(string fieldName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(fieldName));
}
}

#endregion
}

Now we need to bind this to the view. Lets create a view Window1. Here we are specifying Window1ViewModel as data context. The interesting thing is how we should be binding this to the view. As you know that we can not access explicitly implemented properties using object reference, we must be using interface name somehow, in order to specify the property name. When we specify like this, WPF runtime knows that this property is explicitly implemented by data context using the interface specified.

<Window x:Class="INotifyPropertyChanged_ExplicitInterface.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:INotifyPropertyChanged_ExplicitInterface"
DataContext="{DynamicResource ViewModel}"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:Window1ViewModel x:Key="ViewModel" />
</Window.Resources>
<StackPanel>
<TextBox Width="100" Height="100">
<TextBox.Text>
<Binding Path="(local:IWindow1ViewModel.Name)" />
</TextBox.Text>
</TextBox>
</StackPanel>
</Window>

Thursday, September 9, 2010

WPF Priority Binding

With Priority binding, we define a list of bindings arranged in the order of their priorities from top to bottom. The bounded property gets the data from these bindings in this very priority order. The first bindng which gets the data for binding is considered to be the active binding. So the user has some data on the view as soon as the data from first binding becomes available.

The greatest thing is that it doesn't stop there when first data is loaded. If after loading first data, data from any binding higher in the priority list becomes available then WPF uses data from this binding instead.

Lets see a small example in which we use this feature of WPF Binding. Priority Binding is defined for Text property of TextBox. It is bound to any of the three properties from the DataContext including FastValue, MediumValue and SlowValue. When we define priority binding, the first binding is considered to be one with the highest priority. The priorities decrease as we move down.
<Window x:Class="WpfApplicationASynchBinding.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplicationASynchBinding"
DataContext ="{DynamicResource ViewModel}"
Title="Window1" Height="300" Width="300">
<Window.Resources>
<local:Window1ViewModel x:Key="ViewModel" />
</Window.Resources>
<Grid>
<TextBlock Width="200" Height="100" >
<TextBlock.Text>
<PriorityBinding>
<Binding Path="SlowValue" IsAsync="True" />
<Binding Path="MediumValue" IsAsync="True" />
<Binding Path="FastValue" IsAsync="True" />
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</Grid>
</Window>

Now we define the view model which is used as the data context for the above window. You can see that we have defined the three properties as expected by the above view (FastValue, MediumValue and SlowValue). To create the delay effect, we have used Thread.Sleep().

class Window1ViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

string _slowValue = "Slow Value";
public string SlowValue
{
get
{
Thread.Sleep(10000);
return _slowValue;
}
set
{
_slowValue = value;
onPropertyChanged("SlowValue");
}
}

string _mediumValue = "Medium Value";
public string MediumValue
{
get
{
Thread.Sleep(5000);
return _mediumValue;
}
set
{
_mediumValue = value;
onPropertyChanged("MediumValue");
}
}

string _fastValue = "Fast Value";
public string FastValue
{
get
{
Thread.Sleep(2000);
return _fastValue;
}
set
{
_fastValue = value;
onPropertyChanged("FastValue");
}
}


private void onPropertyChanged(string fieldName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(fieldName));
}
}
}

When we run the application, it appears as follows at first:



After 5 seconds, the data from MediumValue becomes available. So it is used by the WPF Binding System. It is assigned to the Text property of the text box.



After 10 seconds, the data from the slowest binding with the highest priority becomes available, so it used now.



Note:
If data from the bindings with different priorities becomes available at the same time then still the data from the binding with highest priority is utilized. In the above example if we had defined a property SlowestValue with the same delay as SlowValue then