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:

  1. <Window.Resources>
  2.     <local:NumAddConverter x:Key="addConv"/>
  3.     <local:ConvParamBindWrapper x:Key="convParamBindWrapper1"
  4.                  Value="{Binding ElementName=slider1,Path=Value}"/>
  5.     <local:ConvParamBindWrapper x:Key="convParamBindWrapper2"
  6.                  Value="{Binding ElementName=slider2,Path=Value}"/>
  7. </Window.Resources>
  8. ...
  9. <Rectangle Width="100" Height="100" Fill="Green"
  10.           Name="rect2" Grid.Column="0"/>
  11. <Rectangle Grid.Column="1"
  12.       Height="{Binding ElementName=rect2,Path=Height,
  13.         Converter={StaticResource addConv},
  14.         ConverterParameter={StaticResource convParamBindWrapper1}}"
  15.         local:ConvParamBindWrapper.
  16.                        UseParamWrapper="FrameworkElement.Height"
  17.         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...

  1. public class ConvParamBindWrapper
  2.                 : Freezable, INotifyPropertyChanged
  3. {
  4. #region UseParamWrapper
  5.  
  6. /// <summary>
  7. /// UseParamWrapper Attached Dependency Property
  8. /// </summary>
  9. public static readonly DependencyProperty UseParamWrapperProperty =
  10.     DependencyProperty.RegisterAttached("UseParamWrapper",
  11.     typeof(DependencyProperty), typeof(ConvParamBindWrapper),
  12.         new FrameworkPropertyMetadata((DependencyProperty)null,
  13.             new PropertyChangedCallback(OnUseParamWrapperChanged)));
  14.  
  15. /// <summary>
  16. /// Gets the UseParamWrapper property.  This dependency property
  17. /// indicates the depency property of the element we want to bind to.
  18. /// </summary>
  19. public static DependencyProperty GetUseParamWrapper(DependencyObject d)
  20. {
  21.     return (DependencyProperty)d.GetValue(UseParamWrapperProperty);
  22. }
  23.  
  24. /// <summary>
  25. /// Sets the UseParamWrapper property.  This dependency property
  26. /// indicates the depency property of the element we want to bind to.
  27. /// </summary>
  28. public static void SetUseParamWrapper(DependencyObject d,
  29.                                       DependencyProperty value)
  30. {
  31.     d.SetValue(UseParamWrapperProperty, value);
  32. }
  33.  
  34. /// <summary>
  35. /// Handles changes to the UseParamWrapper property.
  36. /// </summary>
  37. private static void OnUseParamWrapperChanged(DependencyObject d,
  38.                                 DependencyPropertyChangedEventArgs e)
  39. {
  40.     var dp = e.NewValue as DependencyProperty;
  41.     var elem = d as UIElement;
  42.  
  43.     if (dp != null && elem != null)
  44.     {
  45.         elem.IsVisibleChanged +=
  46.             new DependencyPropertyChangedEventHandler((aaa, bbb) =>
  47.             {
  48.                 var bind = BindingOperations.GetBinding(elem, dp);
  49.                 var bindExp =
  50.                     BindingOperations.GetBindingExpression(elem, dp);
  51.                 var inst = bind.ConverterParameter as ConvParamBindWrapper;
  52.                 inst.PropertyChanged +=
  53.                     new PropertyChangedEventHandler((xxx, yyy) =>
  54.                     {
  55.                         bindExp.UpdateTarget();
  56.                     });
  57.             });
  58.     }
  59. }
  60.  
  61. #endregion
  62.  
  63. #region Value
  64.  
  65. /// <summary>
  66. /// Value Dependency Property
  67. /// </summary>
  68. public static readonly DependencyProperty ValueProperty =
  69.     DependencyProperty.Register("Value", typeof(object),
  70.             typeof(ConvParamBindWrapper),
  71.             new FrameworkPropertyMetadata((object)0,
  72.                 new PropertyChangedCallback(OnValueChanged)));
  73.  
  74. /// <summary>
  75. /// Gets or sets the Value property.  This dependency property
  76. /// indicates the Value that is wrapped.
  77. /// </summary>
  78. public object Value
  79. {
  80.     get { return (object)GetValue(ValueProperty); }
  81.     set { SetValue(ValueProperty, value); }
  82. }
  83.  
  84. /// <summary>
  85. /// Handles changes to the Value property.
  86. /// </summary>
  87. private static void OnValueChanged(DependencyObject d,
  88.                               DependencyPropertyChangedEventArgs e)
  89. {
  90.     ((ConvParamBindWrapper)d).OnValueChanged(e);
  91. }
  92.  
  93. /// <summary>
  94. /// Provides derived classes an opportunity to handle changes to the Value property.
  95. /// </summary>
  96. protected virtual void OnValueChanged(DependencyPropertyChangedEventArgs e)
  97. {
  98.     PropertyChanged(this, new PropertyChangedEventArgs("Value"));
  99. }
  100.  
  101. #endregion
  102.  
  103. public ConvParamBindWrapper()
  104.     : base()
  105. {
  106.     PropertyChanged +=
  107.         new PropertyChangedEventHandler((aaa, bbb) => { });
  108. }
  109.  
  110. protected override Freezable CreateInstanceCore()
  111. {
  112.     //throw new NotImplementedException();
  113.     return new ConvParamBindWrapper();
  114. }
  115.  
  116. #region INotifyPropertyChanged Members
  117.  
  118. public event PropertyChangedEventHandler PropertyChanged;
  119.  
  120. #endregion
  121. }


You can download a test project here.

Have Fun with it!
kick it on DotNetKicks.com