Value Converters, ConvertBack, and Two-way Data Binding
August 27th, 2007 | 4 Comments
In the most recent tutorial, I wrote about value converters, why they are needed, and how to create/use them. In the tutorial, I only covered a simple case where the data binding existed only from the source to the target. The means, modifications to the source result in a modification to the target. In many cases, your data binding will be bi-directional where an update to the target causes an update to the source also. My tutorial does not address that case, so in this post, I’ll briefly cover how to use value converters for two-way data bindings.
For example, here is a simple application that I wrote (download VS2005/C# Express source files) that displays the rounded slider value position in a textbox as I scroll the slider thumb:
While it doesn’t look like it, I am actually using my own value converter. By default, your slider’s values are of type Double. Since I don’t feel like displaying the large number of decimal values that would appear by default, my value converter takes the input and rounds it into an integer. The end result is that you see nice round numbers such as 54 instead of something like 54.1337000.
The slider updating our textbox is one part of our data binding. The second part, which makes our binding two-way, is having our textbox update our slider. Getting back to our example, if I were to enter a number (1-100) in our textbox, the slider’s thumb will position itself based on the number you entered:
The above is an example of two-way data binding where the distinction between the source and the target varies depending on what I am modifying.
In our tutorial, you saw that creating a value converter requires you to use a class that implements the IValueConverter interface. When you implement IValueConverter, two methods are created for you – Convert and ConvertBack. Whether you actually write code for both of those methods depends on the type of data binding involved.
For one-way data binding, you only need to implement the Convert method. For two-way data binding, which is what we have now, our value converter needs to implement both the Convert method as well as the ConvertBack method because our value converter is converting both ways between the target and the source.
The following diagram, expanded on what I showed in the tutorial, illustrates that point:
In the standard one-way binding, the Convert method kicks in. When doing two-way binding, when the Target updates the Source, the ConvertBack method is used instead. While this seems complicated, it really isn’t at all. To prove to you that this is straightforward, let’s look at the code for my value converter called RoundValue.cs:
- using System;
- using System.Collections.Generic;
- using System.Text;
- using System.Windows.Data;
- namespace SliderRoundedValue
- {
- using System.Collections.Generic;
- class RoundValue : IValueConverter
- {
- #region IValueConverter Members
- public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- double inputValue = Math.Round(Double.Parse(value.ToString()));
- return inputValue;
- }
- public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
- {
- try
- {
- double inputValue = Math.Round(Double.Parse(value.ToString()));
- return inputValue;
- }
- catch
- {
- catch
- return 0;
- }
- }
- #endregion
- }
- }
Notice that both my Convert and ConvertBack methods use the same value variable for dealing with data passed into it. The Convert method deals with displaying the rounded value based on my slider’s position. The ConvertBack method deals with taking input from our textbox and positioning our slider accordingly. Because you have a textbox, you are not limited to entering only numbers. When you enter any non-numeric value, your application will crash, so I placed that code in a try/catch statement to avoid that. Beyond using the try/catch statements, there is no difference in the code used in both of these methods. Not all scenarios will be this simple, but at least you have a good idea on how easy this can be.
There really isn’t much more left to elaborate. The tricky part is wrapping your mind around the idea of two-way data binding and when the Convert and ConvertBack methods are used. To test out what I explained, you can download the Visual C# Expression 2005-based source files by clicking the following link: http://www.kirupa.com/blend_wpf/code/SliderRoundedValue.zip
Cheers!
Kirupa





September 17th, 2007 at 8:52 pm
Hi,
How to set the ValueConverter of a binding in code?
Regards,
Parham.
September 17th, 2007 at 9:01 pm
Parham – simply look at the XAML in my source file
You call the file ValueConverter via: Converter={StaticResource RoundValue}
May 23rd, 2008 at 6:23 am
I think you will find the TryParse much more efficient. You don’t even need the if you could use return Math.Round(newval); after the TryParse, I just wanted to show the full format of TryParse.
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double newval = 0;
if (Double.TryParse(value.ToString(),System.Globalization.NumberStyles.Number,culture , out newval))
{
return Math.Round(newval);
}
else
{
return newval;
}
}
May 23rd, 2008 at 10:38 am
Hi Nigel – thanks for that tip. I never considered using TryParse
When you mention it is more efficient, it is because we no longer have to use the more costly try/catch, right?
Cheers!
Kirupa