A common question on the WPF forums is how to pass the control itself into a ValueConverter that is acting on one of it's properties.

This example shows how that is achieved with three examples.
 
The main trick here is to use a MultiValueConverter and a MultiBinding, but where it is defined in resources is very important.

Example 1

The first example passes in a bound value from the code-behind and the control itself through a MultiBinding, to the MultiValueConverter. 


<TextBlock x:Name="tb1" Margin="20">
    <TextBlock.Text>
        <MultiBinding Converter="{StaticResource MyConverter}">
            <Binding RelativeSource="{RelativeSource Self}"/>
            <Binding Path="MyValue"/>
        </MultiBinding>
    </TextBlock.Text>
</TextBlock>


The main thing to note here is the RelativeSource of the first binding, being {RelativeSource Self}.
This will pass the control itself into the converter.

Here is the converter:

public class MyConverter : IMultiValueConverter
{
    FrameworkElement myControl;
    object theValue;
 
    public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        myControl = values[0] as FrameworkElement;
        theValue = values[1];
 
        return myControl.Name + " : " + values[1];
    }
 
    public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        return new object[] { null, myControl.Name + " : " + theValue };
    }
}


The Convert method just takes the first value and converts it into a FrameworkElement, so it can take the control's name (proving the control was passed in correctly) which it joins to the second parameter. It also keeps a local copy of the values for the ConvertBack method discussed later in example 3.

 

Notice the values array in MultiValueConverters order the bidings by the same order they are shown in the markup code.

Example 2

The second example is similar in that it sets a property of UserControl1, but this example includes a couple of extras.

Firstly you will notice the DependancyPropertyChangedCallback parameter of the DependancyProperty constructor is used. Any changes to the MyUserControlvalue property will cause a call to MyUserControlValueChanged. In the example, this method takes the new value (e.NewValue) and adds it to a datestamp into the third textbox of UserControl1.
Also notice the control itself was passed in, this is where you can act on the specific object instance.

 

public static readonly DependencyProperty MyUserControlValueProperty =
    DependencyProperty.Register("MyUserControlValue", typeof(string), typeof(UserControl1), new UIPropertyMetadata(null, MyUserControlValueChanged));
 
static void MyUserControlValueChanged(DependencyObject dp, DependencyPropertyChangedEventArgs e)
{
    var uc1 = dp as UserControl1;
    uc1.MyChangedDateString = e.NewValue + " - " + DateTime.Now.ToString();
}

This user control is used just the same as the previous example:This user control is used just the same as the previous example:This user control is used just the same as the previous example:

<local:UserControl1 x:Name="uc1" Background="Yellow">
    <local:UserControl1.MyUserControlValue>
        <MultiBinding Converter="{StaticResource MyConverter2}">
            <Binding RelativeSource="{RelativeSource Self}"/>
            <Binding Path="MyValue"/>
        </MultiBinding>
    </local:UserControl1.MyUserControlValue>
</local:UserControl1>

However the converter in this example shows how once you have the control, the converter can safely do stuff on it like calling it's methods.

public class MyConverter2 : IMultiValueConverter
{
    public object Convert(object[] values, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        var uc = values[0] as UserControl1;
        uc.MyShowTextMethod("Set from converter");
 
        return uc.Name + " : " + values[1];
    }
 
    public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new System.NotImplementedException();
    }
}

 

Example 3

This is in response to a follow-up question where the poster wanted to use the passed in control in the ConvertBack method. As shown above, the passed in values are kept for use with the ConvertBack method.

It is important to understand how and WHERE you refer to the Converter, not as one StaticResource, but as several localised resources. If it is defined in the top Window/Page level resources, all controls will use the same converter instance, so any passed in values will be written over by the next control. When you try to convert back, you will get whatever the last control to use Convert was.

Instead, you have to define the static resource at CONTROL LEVEL, so only that control uses THAT instance of the converter.This is an important concept to know.

<TextBox x:Name="tb1" Margin="20">
    <TextBox.Resources>
        <local:MyConverter x:Key="MyConverter"/>
    </TextBox.Resources>
    <TextBox.Text>
        <MultiBinding Converter="{StaticResource MyConverter}" UpdateSourceTrigger="PropertyChanged">
            <Binding RelativeSource="{RelativeSource Self}" Mode="OneTime"/>
            <Binding Path="MyValue" />
        </MultiBinding>
    </TextBox.Text>
</TextBox>
 
<TextBox x:Name="tb2" Margin="20">
    <TextBox.Resources>
        <local:MyConverter x:Key="MyConverter"/>
    </TextBox.Resources>
    <TextBox.Text>
        <MultiBinding Converter="{StaticResource MyConverter}" UpdateSourceTrigger="PropertyChanged">
            <Binding RelativeSource="{RelativeSource Self}" Mode="OneTime"/>
            <Binding Path="MyValue2" />
        </MultiBinding>
    </TextBox.Text>
</TextBox>


This available in a demo project here.


This small article is part of a series of WPF "How To" articles, in response to real user questions on the MSDN WPF Forum.