Home > WPF > A base class for custom WPF binding markup extensions

A base class for custom WPF binding markup extensions

April 16th, 2008

Already tried to extend the Binding or BindingBase classes in order to write your own custom bindings? And failed because BindingBase.ProvideValue is sealed? Me too…

The result is a MarkupExtension that works around the issue that you cannot properly extend the Binding class. Basically, it allows you to write binding expressions with the usual syntax without having to worry about the underlying plumbing. Here’s a sample binding that adds an additional LookupKey property:

<TextBox Name="txtZipCode"
         Text="{local:LookupExtension Path=ZipCode,
                                      Mode=TwoWay,
                                      UpdateSourceTrigger=PropertyChanged,
                                      LookupKey=F5}"
/>

Decorating the Binding class

As extending the Binding class did not work, I tried a different approach:

  • Create a class that extends MarkupExtension rather than BindingBase. This class provides all the properties that are needed for a binding expression (Source, Path, Converter, …).
  • Based on defined binding properties, the extension class internally creates a regular Binding and associates it with the targeted dependency object.

I wanted it to look somehow like this (dummy code!):

public class MyCustomExtension : MarkupExtension
{
  public override object ProvideValue(IServiceProvider provider)
  {
    //we only use this extension on textboxes
    TextBox tb = GetTextBoxFromProvider(provider);

    //create a binding and associate it with the text box
    Binding binding = CreateBinding(this.Source, this.Path);
    tb.SetBinding(TextBox.TextProperty, binding);

    //return a valid value
    return ...;
  }
}

And guess what – that worked :)

The result is an abstract base class that provides pretty much everything you need to create your custom binding classes. The BindingDecoratorBase provides properties for all kinds of binding expressions (Source, Path, Converter etc.) and handles binding creation and association with the targeted dependency object for you:

image

Basically, the class maintains its own binding class and just forwards the binding statements. For example, here’s the declaration of the Path property:

[DefaultValue(null)]
public PropertyPath Path
{
  get { return binding.Path; }
  set { binding.Path = value; }
}

Custom Binding Sample

Here’s a simple sample: Let’s say we have a TextBox that displays the ZipCode property of a bound item. The XAML for this bound control looks like this:

<TextBox Name="txtZipCode"
         Text="{Binding Path=ZipCode}"
/>

However, we want to interfere with the binding in order to add some additional value. For this example, we’d like to register the bound control with some kind of handler class. We could also do this with an attached property, but this is more fun ;)

First, I created a custom extension called LookupExtension that derives from BindingDecoratorBase. BindingDecoratorBase provides all binding properties out of the box, so the binding expression itself (Path=ZipCode) remains intact. The only thing I had to change in XAML was the extension name and add the custom property for my extension (LookupKey):

<TextBox Name="txtZipCode"
         Text="{local:LookupExtension Path=ZipCode,
                                      LookupKey=F5}"
/>

As LookupExtension derives from BindingDecoratorBase, it is ensured that in the end, the text box will be bound to the ZipCode property just like with the original regular binding expression.

Below is a first implementation which does not yet add any additional value. Therefore, this extension would behave exactly like the original binding – the ZipCode property of the bound data item is displayed, and updating the TextBox changes the bound property value:

public class LookupExtension : BindingDecoratorBase
{
  //A property that can be set in XAML
  public string LookupKey { get; set; }

  public override object ProvideValue(IServiceProvider provider)
  {
    //delegate binding creation etc. to the base class
    return base.ProvideValue(provider);
  }
}

So what’s left is adding some custom code to the extension. Below is the complete sample. Basically, the bound control (the text box of the sample) is determined by invoking TryGetTargetItems and then registered with an InputHandler. That’s it:

public class LookupExtension : BindingDecoratorBase
{
  //A property that can be set in XAML
  public string LookupKey { get; set; }

  public override object ProvideValue(IServiceProvider provider)
  {
    //delegate binding creation etc. to the base class
    object val = base.ProvideValue(provider);

    //try to get bound items for our custom work
    DependencyObject targetObject;
    DependencyProperty targetProperty;
    bool status = TryGetTargetItems(provider, out targetObject,
                                              out targetProperty);

    if (status)
    {
      //associate an input listener with the control
      InputHandler.RegisterHandler(targetObject, LookupKey);
    }

    return val;
  }
}

Note the status flag in the snippet above! ProvideValue is also invoked at design time (within Visual Studio). In this case, the provider parameter is null, so be careful to validate your parameters or you’ll end up with a broken designer.

 

Problem: Attribute syntax with resources

During the implementation of the sample, I came across an annoying issue: You cannot nest static or dynamic resources within a custom markup extension due to a framework bug. This means that if you wanted to set the Source property explicitly, you could not write it like this:

<TextBox Name="txtZipCode"
         Text="{local:LookupExtension Source={StaticResource MyAddress}
                                      Path=ZipCode,
                                      LookupKey=F5}"
/>

The above snippet does not compile due to a bug I described here. As a result, you have to fall back to property element syntax if you need to explicitly setting the Source property or other resources (e.g. Converter):

<TextBox Name="txtZipCode">
  <TextBox.Text>
    <local:LookupExtension Source="{StaticResource MyAddress}"
                           Path="ZipCode"
                           LookupKey="F5" />
  </TextBox.Text>
</TextBox>

 

Source Code / Sample

I’ve assembled a simple project that contains the BindingDecoratorBase class and the LookupExtension I used as a sample (VS 2008 project).

You can download it here: custom-bindings.zip

Markup Extension Sample

 


Author: Categories: WPF Tags: ,
  1. Liviu
    July 25th, 2008 at 19:17 | #1

    Hi ,

    I tried deriving from your BindingDecoratorBase. what is strange, is that changing the source property does not trigger an update of the control. Do you know what might be the cause?
    The ProvideValue method is called only once, whrn the window is rendered but is not updated if DataContext is changed, or when the object property changes….
    Any help would be great…

  2. csharpriot
    November 3rd, 2008 at 17:28 | #2

    Great article!

    how can i set the binding in c# code?
    mytextbox.SetBinding(TextBox.TextProperty, myLookupExtension) doesn’t work :(

  3. John White
    December 27th, 2008 at 12:00 | #3

    Hi. Well this is an interesting article, but unfortunately not suitable for my current task. The problem i have to deal with now, is to establish binding from an entity with a dynamicaly composed set of “properties” and to a standard DependencyObject. The properties are not CLR properties, lets say its something like a Hastable. Standard Binding class is unusable there because there is no way to notify Binding about source value change. The problem is in PropertyPath class, since we dont really have CLR property, but rather and indexer. Here is an example to show what im talking about:
    … somewhere in code …
    public Hastable ht;
    ….
    ht["Prop1"] = “Property 1 value”
    ht["Prop2"] = 2;

    Now sample XAML of data template, using standard binding classes where data context is hastable:

    This will work only once, and as values in hashtable changing there will be no autoupade of target properties. INotifyCollectionChange will not help also, since we bind not to collection itself, but to its item.
    Another approach is to implement custom data object class like

    class DataContainer : INotifyPropertyChanged
    {
    private T m_Value;

    public T Value
    {
    get { return m_Value; }
    set
    {
    if (m_Value != value)
    {
    m_Value = value;
    PropertyChanged(this, “Value”);
    }
    }
    }

    public event EventHandler PropertyChanged;
    }

    and to set hastable items to instances of that class. That may work. But as number of “properties” and instances of property owners grows, and also as frequency of property changes do, perfomance and memory usage strike of such approach becomes unacceptable.

    Another option – is to create instances of source DependencyProperties from non-static code, but:
    1) There is no way to unregister a dependency property.
    2) There is no actual CLR class to associate property with. Generate classes with reflection API too costy.

    So the perfect approach would be to impelement custom Binding class, which knows how to aquire data from a special data context and which has a way to synchronize values in non-standard way.
    But … THE WHOLE DAMN THING IS EITHER INTERNAL OR SEALED! And that makes me a very very sad panda… GG Microsoft…

    P.S. Personally i’d called WPF 3.0 – “WPF internal sealed edition v3.0″ since ALOT of stuff in there hidden or explicitly denied from usage by developer.

  4. December 28th, 2008 at 19:34 | #4

    Hi John
    Binding to indexers does work with WPF. If you are binding to an indexer, you don’t have to fire collection change events but rather property change events according to INotifyPropertyChanged interface.

    Of course, Hashtable doesn’t help you here – accordingly, I’d say that a ViewModel wrapper is the way to go. And the good doctor might just have the cure ;)
    http://www.drwpf.com/blog/Home/tabid/36/EntryID/8/Default.aspx

    HTH,
    Philipp

  5. Harry
    April 18th, 2009 at 14:46 | #5

    Hi Philipp,
    Thanks a lot for the useful article. However, I don’t know how to execute (or call) a storyboard (written in XAML) when an event built by myself is fired. In detail, I create an event in a class which is a attribute of my mainwindow. I want a ObjectAnimationUsingKeyFrames (built in XAML) in action when the event fired. Would you please give me some advice?
    P/s: I’m sorry if the question is awkward. I’m just new in WPF.

  6. Disore
    August 28th, 2009 at 09:22 | #6

    Sorry for the late comment, but I got forwarded here from a recently published CodeProject article.

    My question is how BindingDecoratorBase, and the implementation of LookupExtension, handles ControlTemplates. I tried putting txtZipCodeCustom in a control template and the demo stops working. I guess it has to do with how controls load within the ControlTemplate. Do you know a good solution to the problem?

  7. Clint
    December 26th, 2009 at 06:55 | #7

    Hi Philipp,
    Your article has helped me big time – Thanks!

    Also, ‘Attribute Syntax’ worked for me when I placed the Custom MarkupExtension in a separate assembly to the application assembly. I have not looked into why this works, but for me it does!

    HTH
    Clint

  8. December 26th, 2009 at 11:06 | #8

    Thanks for the info, Clint! I’ll check if I can reproduce the behavior and update the article accordingly.

    Cheers,
    Philipp

  9. Blazer51
    April 21st, 2011 at 05:08 | #9

    I was able to use the attribute syntax with this markup extension too, when i placed the extension in another assembly

  10. Blazer51
    April 21st, 2011 at 05:13 | #10

    Another question for me is: how can i use this extension in a style?

    will throw an exception:

    XamlParserException: “Binding” kann nicht für die Eigenschaft “Value” vom Typ “Setter” festgelegt werden. “Binding” kann nur für eine “DependencyProperty” eines “DependencyObject” festgelegt werden.

  11. Blazer51
    April 21st, 2011 at 05:15 | #11

    Sorry translation of the exception: You can’t setup a “Binding” for the Property “Value” of type “Setter”. “Binding” can only be used for “DependencyProperty” of a “DependencyObject”

  12. Tobias
    August 17th, 2011 at 12:11 | #12

    About the issue with Templates:
    If your targetObject == null (or in real it is SharedDP) return the MarkupExtension itself and it will get called once the control which uses the template will get instantiated and then you will get proper values for targetObject.

  13. Jeff Dege
    May 17th, 2012 at 16:19 | #13

    I’m having a problem with converters. I’ve derived a couple of Binding classes from BindingDecoratorBase, and I’ve had no trouble with any of them, unless I try to specify a Converter for one. E.g.:

    I get an error: Unknown property ‘Converter’ for type ‘MS.Internal.Markup.MarkupExtensionParser+UnknownMarkupExtension’ encountered while parsing a Markup Extension.

  14. December 19th, 2012 at 23:49 | #14

    Custom bindings are awesome. I created some to simplify and essentially replace the default WPF binding. For example, if you were binding to a template instead of writing this:

    {Binding Path=PathToProperty, RelativeSource={RelativeSource TemplatedParent}}

    You can write this:

    {BindTo Template.PathToProperty}

    You can find it here:

    http://www.simplygoodcode.com/2012/08/simpler-wpf-binding.html

  1. May 13th, 2008 at 14:16 | #1
  2. December 1st, 2008 at 23:10 | #2
  3. May 26th, 2009 at 20:08 | #3
  4. May 28th, 2009 at 00:45 | #4
  5. August 5th, 2009 at 20:35 | #5
  6. March 16th, 2010 at 16:22 | #6
  7. March 30th, 2010 at 05:49 | #7
  8. October 15th, 2012 at 14:48 | #8
  9. November 15th, 2012 at 21:38 | #9
  10. November 5th, 2013 at 14:06 | #10