Aug
13
Using DataBinding in a ConverterParameter
Category: WPF
Posted by: Martin Rauscher
I'm starting forthright with something that is generally considered impossible: Using DataBinding in a ConverterParameter.
Those of you who are relatively new to WPF might ask why somebody wanted to do this.
Well I'm quite new to WPF myself, so i can't say if this is best practice, but with Converters you can simply do EVERYTHING! Many things that would be quite hard or even impossible in XAML can be done quite easily with Converters. You will find a nice example in my post about WPFTriangelo.
Marlon Grech, a WPF Disclipe, already wrote a post on this topic and eventually found a solution to this quite hard problem.
But his solution uses reflection...
But I found another way... without reflection!
Update: I formatted the code nicer. I hope you didn't see it while it was totally messed up
My first thought after reading Marlon's article was, why not using a wrapper opject that you CAN bind to, and use this as ConverterParameter instead of your original object?
And this is exactly what I did:
I created a class ConvParamBindWrapper that has a DepencyProperty of type Object, that holds the Value, and an AttachedProperty that is used to initialize the binding.
Remark: My class inherits from Freezable and from INotifyPropertyChanged as I thought I might need some of the functionality. But I haven't tested if I really need them now.
The final code can be used like this:
You simply specify what DepencyProperty and what WrapperObject are used.
I haven't tried to use this with multiple properties on one object... TBC
This is the hole code of the wrapper object:
The most interesting part lies in OnUseParamWrapperChanged. This is also where it gets a bit hacky and maybe this isn't as reusable as I think...
You can download a test project here.
Have Fun with it!
Those of you who are relatively new to WPF might ask why somebody wanted to do this.
Well I'm quite new to WPF myself, so i can't say if this is best practice, but with Converters you can simply do EVERYTHING! Many things that would be quite hard or even impossible in XAML can be done quite easily with Converters. You will find a nice example in my post about WPFTriangelo.
Marlon Grech, a WPF Disclipe, already wrote a post on this topic and eventually found a solution to this quite hard problem.
But his solution uses reflection...
But I found another way... without reflection!
Update: I formatted the code nicer. I hope you didn't see it while it was totally messed up
My first thought after reading Marlon's article was, why not using a wrapper opject that you CAN bind to, and use this as ConverterParameter instead of your original object?
And this is exactly what I did:
I created a class ConvParamBindWrapper that has a DepencyProperty of type Object, that holds the Value, and an AttachedProperty that is used to initialize the binding.
Remark: My class inherits from Freezable and from INotifyPropertyChanged as I thought I might need some of the functionality. But I haven't tested if I really need them now.
The final code can be used like this:
- <Window.Resources>
- <local:NumAddConverter x:Key="addConv"/>
- <local:ConvParamBindWrapper x:Key="convParamBindWrapper1"
- Value="{Binding ElementName=slider1,Path=Value}"/>
- <local:ConvParamBindWrapper x:Key="convParamBindWrapper2"
- Value="{Binding ElementName=slider2,Path=Value}"/>
- </Window.Resources>
- ...
- <Rectangle Width="100" Height="100" Fill="Green"
- Name="rect2" Grid.Column="0"/>
- <Rectangle Grid.Column="1"
- Height="{Binding ElementName=rect2,Path=Height,
- Converter={StaticResource addConv},
- ConverterParameter={StaticResource convParamBindWrapper1}}"
- local:ConvParamBindWrapper.
- UseParamWrapper="FrameworkElement.Height"
- Width="100" Fill="Red" Name="rect"/>
You simply specify what DepencyProperty and what WrapperObject are used.
I haven't tried to use this with multiple properties on one object... TBC
This is the hole code of the wrapper object:
The most interesting part lies in OnUseParamWrapperChanged. This is also where it gets a bit hacky and maybe this isn't as reusable as I think...
- public class ConvParamBindWrapper
- : Freezable, INotifyPropertyChanged
- {
- #region UseParamWrapper
- /// <summary>
- /// UseParamWrapper Attached Dependency Property
- /// </summary>
- public static readonly DependencyProperty UseParamWrapperProperty =
- DependencyProperty.RegisterAttached("UseParamWrapper",
- /// <summary>
- /// Gets the UseParamWrapper property. This dependency property
- /// indicates the depency property of the element we want to bind to.
- /// </summary>
- public static DependencyProperty GetUseParamWrapper(DependencyObject d)
- {
- return (DependencyProperty)d.GetValue(UseParamWrapperProperty);
- }
- /// <summary>
- /// Sets the UseParamWrapper property. This dependency property
- /// indicates the depency property of the element we want to bind to.
- /// </summary>
- public static void SetUseParamWrapper(DependencyObject d,
- DependencyProperty value)
- {
- d.SetValue(UseParamWrapperProperty, value);
- }
- /// <summary>
- /// Handles changes to the UseParamWrapper property.
- /// </summary>
- private static void OnUseParamWrapperChanged(DependencyObject d,
- DependencyPropertyChangedEventArgs e)
- {
- var dp = e.NewValue as DependencyProperty;
- var elem = d as UIElement;
- if (dp != null && elem != null)
- {
- elem.IsVisibleChanged +=
- {
- var bind = BindingOperations.GetBinding(elem, dp);
- var bindExp =
- BindingOperations.GetBindingExpression(elem, dp);
- var inst = bind.ConverterParameter as ConvParamBindWrapper;
- inst.PropertyChanged +=
- {
- bindExp.UpdateTarget();
- });
- });
- }
- }
- #endregion
- #region Value
- /// <summary>
- /// Value Dependency Property
- /// </summary>
- public static readonly DependencyProperty ValueProperty =
- /// <summary>
- /// Gets or sets the Value property. This dependency property
- /// indicates the Value that is wrapped.
- /// </summary>
- public object Value
- {
- get { return (object)GetValue(ValueProperty); }
- set { SetValue(ValueProperty, value); }
- }
- /// <summary>
- /// Handles changes to the Value property.
- /// </summary>
- private static void OnValueChanged(DependencyObject d,
- DependencyPropertyChangedEventArgs e)
- {
- ((ConvParamBindWrapper)d).OnValueChanged(e);
- }
- /// <summary>
- /// Provides derived classes an opportunity to handle changes to the Value property.
- /// </summary>
- protected virtual void OnValueChanged(DependencyPropertyChangedEventArgs e)
- {
- }
- #endregion
- public ConvParamBindWrapper()
- : base()
- {
- PropertyChanged +=
- }
- protected override Freezable CreateInstanceCore()
- {
- //throw new NotImplementedException();
- }
- #region INotifyPropertyChanged Members
- public event PropertyChangedEventHandler PropertyChanged;
- #endregion
- }
You can download a test project here.
Have Fun with it!


Marlon Grech wrote:
nice! :)