Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / WPF

WPF ValueConverter to Convert to Correct Type

5.00/5 (5 votes)
5 Apr 2018CPOL2 min read 13.1K  
Normally, there is no need to ensure that types exactly match when using a Binding. For instance, the Control property double to and int in a ViewModel

Introduction

I had developed a custom control that contained a Slider and was Binding the Slider Value property through a DependencyProperty of the same type (it could have been of Type object) through a TemplatedParent Binding to a ViewModel that had an int property for the Slider Value. What surprised me is that this did not work because a Type conversion error--apparently in this case, the TypeDescriptor was not being used to convert to the correct type. I could not just change the Type in the ViewModel because a special class was being used to retrieve and update the value, and the format this value was being stored as was int. I had worked with TypeDescriptor conversion in IValueConverter classes before, and decided I could easily fix this with a ValueConverter using a TypeDescrirptor:

C#
public class TypeValueConverter : MarkupExtension, IValueConverter
{
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ConvertToType(value, targetType);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return ConvertToType(value, targetType);
    }

    private static object ConvertToType(object value, Type targetType)
    {
        try
        {
            if (targetType == typeof(object)) return value;
            var converter = TypeDescriptor.GetConverter(targetType);
            return converter.ConvertFrom(value.ToString());
        }
        catch
        {
            var errorValue = value;
            throw new Exception(
                $"Failed in attempt to convert {errorValue} to type
                {targetType.Name} using TypeConverter in class TrueFalseValues");
        }
    }
}

Using the Code

As with any IValueConverter, to use it, include the Converter argument in the Binding definition. Since this class not only derives from IValueConverter, but also MarkupExtension, can directly use the converter without defining it:

XML
<local:BaseSlider Grid.Row="3"
                  Grid.Column="1"
                  Height="40"
                  HorizontalAlignment="Stretch"
                  VerticalAlignment="Center"
                  NewValue="{Binding SliderValue2.Value,
                                     Converter={local:TypeValueConverter}}" />

Points of Interest

The interesting thing about the whole problem I encountered is that I was getting a Type error when I should not have since WPF is supposed to handle basic conversions which are supported through the TypeDescriptor, and there is support between most number types, such as between int and double. In this case, I had a Generic class that kept the actual value in a Value property. What I had was a custom Control that contained a double Binding to the Slider Value property, with, in this instance, to a ViewModel int Type property. So to solve this problem in the application I was working on, I created this converter. Then I tried to reproduce the problem in a separate simplified project to include with this tip, I could not do. I even tried to move a lot of the code over, but not everything since I really did not want to have to include the Rx (Linq to Events) framework which was being used. So, it is very unlikely that someone will need this converter. At this point, I do not have a sample that will show this problem but will probably continue to work on this problem to try and reproduce the problem.

History

  • 04/05/2018: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)