Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

WPF Dependency Property: Compatible with XAML Binding and Code Behind Binding.

0.00/5 (No votes)
13 Dec 2010 1  
An easy guideline to write WPF dependency property which is compatible with XAML binding and code behind binding.

Introduction

WPF and dependency property are indispensable parts.

Without dependency property and MVVM, you are almost nowhere in WPF development. But improper use of dependency property can create a nightmare.

Let’s take the following example.

Suppose we have created a custom media player control and we want to bind the Source property from XAML. It is to be noted that once the source property is set, we need to do some additional related thing.

Here is the initial code snippet of Source Dependency Property:

public Uri Source
{
 get { return (Uri)GetValue(SourceProperty); }
 set
 {
       SetValue(SourceProperty, value);
       if (MediaElement != null)
       {
            SetMediaElementSource();
       }
 }
}

// Using a DependencyProperty as the backing store for Source. 
// This enables animation, styling, binding, etc...
   public static readonly DependencyProperty SourceProperty =
        DependencyProperty.Register("Source", typeof (Uri), typeof (MediaPlayer));

And here is our XAML:

<media:MediaPlayer Source="{Binding Source}"   
x:Name="MainPlayer"></media:MediaPlayer>

Now if we run our application, we shall see that none of the code written after SetValue(SourceProperty, value); will execute. The reason behind this is that if we set the property from XAML, the SetValue() method is called directly. So our player will not work if we bind the source property from XAML! We can easily overcome this problem if we use the following overloaded version of DependencyProperty.Register method.

// Using a DependencyProperty as the backing store for Source.  
// This enables animation, styling, binding, etc...
   public static readonly DependencyProperty SourceProperty =
        	DependencyProperty.Register("Source", typeof(Uri), 
	typeof(MediaPlayer), new FrameworkPropertyMetadata(OnMediaSourceChanged));

   private static void OnMediaSourceChanged
	(DependencyObject d, DependencyPropertyChangedEventArgs e)
   {
        var player = d as MediaPlayer;
        if (player != null) player.Source = e.NewValue as Uri;
   }

As you can see, the new FrameworkPropertyMetaData is nothing but a method which is fired once the Source property is changed irrespective of whether it is changed from XAML or code behind. Since we are setting the Source property in OnMediaSourceChanged method so now the Set method of source will execute with all business logic! Seems our problem is solved!! But the fact is it is not solved yet rather it gives birth to another problem. If we set the Source property from the code behind, the Set property of Source along with related code written in Set method will be executed twice, one for setting it from code behind and another from OnMediaSourceChanged method. The solution to this problem is, keep the Set property free from any business logic (or any code!). Rather whatever code is needed to execute, keep those in some separate method and call that method from OnMediaSourceChanged. Here comes the code that is fully compatible with XAML binding and code behind.

/// <summary>
/// Gets or sets the source.
/// </summary>
/// <value>The source.</value>
public Uri Source
{
    get { return (Uri)GetValue(SourceProperty); }
    set
    {
        SetValue(SourceProperty, value);
    }
}

// Using a DependencyProperty as the backing store for Source.  
// This enables animation, styling, binding, etc...
public static readonly DependencyProperty SourceProperty =
    DependencyProperty.Register("Source", typeof(Uri), typeof(MediaPlayer), 
    new FrameworkPropertyMetadata(OnMediaSourceChanged));
    
/// <summary>
/// Called when [media source changed].
/// </summary>
/// The d.
/// The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> 
/// instance containing the event data.
private static void OnMediaSourceChanged
	(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
    var player = d as MediaPlayer;
    if (player != null)
    {
        player.Source = e.NewValue as Uri;
        player.PostSourceSetupWork();
    }
}

/// <summary>
/// Posts the source setup work.
/// </summary>
public void PostSourceSetupWork()
{
    if (MediaElement != null)
    {
        mediaElement.Pause();
        SetMediaElementSource();
    }
}

History

  • 13th December, 2010: Initial post

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here