Click here to Skip to main content
15,867,939 members
Articles / Desktop Programming / WPF

Binding on a Property which is not a DependencyProperty

Rate me:
Please Sign up or sign in to vote.
4.75/5 (8 votes)
8 Apr 2010Ms-PL2 min read 55.1K   18   3
A lot of controls expose properties which are not DependencyProperties and then you can’t put a binding on it. On some other cases, you only have a getter as accessor and you can’t put a binding on it too...

A lot of controls expose properties which are not DependencyProperties and then you can't put a binding on it. In some other cases, you only have a getter as accessor and you can't put a binding on it too…

This is for example the case for the ribbon’s group of the office ribbon or the converter’s parameter.

If you ever tried to do so, you surely had an exception thrown:

A 'Binding' cannot be set on the 'SetCEDEJDED' property of type 'Tralala'.
A 'Binding' can only be set on a DependencyProperty of a DependencyObject.

In this post, we will discover a work-around…

The main idea is to use a kind of proxy/observer (a definition can be found in this post) which will reflect every change on the source object to the target object and vice versa.

Here are the main parts of the solution.

Specification: The XAML Code We'll Use

Here is the code snippet which describes how we will use our proxy in the XAML. There will be no code-behind.

XML
<Window x:Class="BindOnNonDependencyProperty.MainWindow" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:us="clr-namespace:BindOnNonDependencyProperty"
    Title="BindOnNonDependencyProperty" >
  <DockPanel >
    <TextBox x:Name="myTextBox" DockPanel.Dock="Top"  />
    <TextBox x:Name="monTextBlockCible"  DockPanel.Dock="Top"  />
    <us:ExtendedBinding Source="{Binding ElementName=myTextBox,Path=Text,Mode=TwoWay}"
              Target="{Binding ElementName=monTextBlockCible,Path=Text,Mode=TwoWay}"
              />
  </DockPanel>
</Window>

The Correct Base Class for our Proxy/Observer

We will call it ExtendedBinding and it must be inheriting from DependencyObject at last to be able to own DependencyProperty. But the only way to add a DependencyObject into our XAML is to add it into a resourceDictonary.

This is a drawback because, by doing it, it will no more be in the control's tree and then it will be impossible to make a binding on one of its properties. Note that it's still possible to use it as a Target from another place in our XAML, but you can't do a Binding on one of its properties. This code will not work:

XML
<Windows.Resources>
   <MyDependencyObject x:Key="myKey" 
	MyProperty="{Binding Tralala, ElementName=myTarget}" />
</Windows.Resources>

Then to put it inside the control's tree, we only had to make it a UIElement will you say... No because in the actual version of the Framework, you won't have inheritance of the DataContext and the use of the 'ElementName' binding will be prohibited. Hopefully, there is a solution, our proxy have to inherit from FrameworkElement and everything will work fine!

The DependencyProperties

We will add two dependencyProperties, one will be the target and the second will be the source.
These DPs will be customized by using the FrameworkPropertyMetadata to enable these features:

  • Binding will be done using the TwoWay mode
  • The UpdateSourceTrigger used will be the PropertyChanged event

How It Works

The core of our proxy is to override the DependencyObject's OnPropertyChanged method. Each change on the source or the target will update its counterpart.

We have to take care not to fall into a loop: when we will update the target or the source, we'll also raise a PropertyChanged event and we must ignore this one....

Final Code

C#
public class ExtendedBinding : FrameworkElement
  {
    #region Source DP
    //We don't know what will be the Source/target type so we keep 'object'.
    public static readonly DependencyProperty SourceProperty =
      DependencyProperty.Register("Source", typeof(object), typeof(ExtendedBinding),
      new FrameworkPropertyMetadata()
      {
        BindsTwoWayByDefault = true,
        DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
      });
    public Object Source
    {
      get { return GetValue(ExtendedBinding.SourceProperty); }
      set { SetValue(ExtendedBinding.SourceProperty, value); }
    }
    #endregion
 
    #region Target DP
      //We don't know what will be the Source/target type so we keep 'object'.
    public static readonly DependencyProperty TargetProperty =
      DependencyProperty.Register("Target", typeof(object), typeof(ExtendedBinding),
      new FrameworkPropertyMetadata()
      {
        BindsTwoWayByDefault = true,
        DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged,
      });
    public Object Target
    {
      get { return GetValue(ExtendedBinding.TargetProperty); }
      set { SetValue(ExtendedBinding.TargetProperty, value); }
    }
    #endregion
 
    protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
    {
      base.OnPropertyChanged(e);
      if (e.Property.Name == ExtendedBinding.SourceProperty.Name)
      {
	//no loop wanted
        if (!object.ReferenceEquals(Source, Target))
          Target = Source;
      }
      else if (e.Property.Name == ExtendedBinding.TargetProperty.Name)
      {
	//no loop wanted
        if (!object.ReferenceEquals(Source, Target))
          Source = Target;
      }
    }
  }
Shout it kick it on DotNetKicks.com
This article was originally posted at http://blog.lexique-du-net.com/index.php

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Software Developer http://wpf-france.fr
France (Metropolitan) France (Metropolitan)
Jonathan creates software, mostly with C#,WPF and XAML.

He really likes to works on every Natural User Interfaces(NUI : multitouch, touchless, etc...) issues.



He is awarded Microsoft MVP in the "Client Application Development" section since 2011.


You can check out his WPF/C#/NUI/3D blog http://www.jonathanantoine.com.

He is also the creator of the WPF French community web site : http://wpf-france.fr.

Here is some videos of the projects he has already work on :

Comments and Discussions

 
GeneralMy vote of 5 Pin
Tokinabo6-Aug-20 13:01
professionalTokinabo6-Aug-20 13:01 
QuestionHow to use it in view model of mvvm Pin
Aravind Koniki13-Jun-12 2:19
Aravind Koniki13-Jun-12 2:19 
QuestionGreat ! Pin
glob3r12-Mar-12 9:42
glob3r12-Mar-12 9:42 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.