Specify target type for IValueConverter

denver picture denver · Jul 7, 2015 · Viewed 7.8k times · Source

I have a situation where I am using a multi-value converter. The values passed to it are themselves being converted.

<MenuItem>
    <MenuItem.IsEnabled>
        <MultiBinding Converter="{StaticResource BooleanAndConverter}">
            <Binding Path="Prop1" Converter="{StaticResource Converter1}" />
            <Binding Path="Prop2" Converter="{StaticResource Converter1}" />
        </MultiBinding>
    </MenuItem.IsEnabled>
</MenuItem

Converter1 contains some error checking to confirm that it is called with a valid target type. It throws an exception if not, as this is a developer error and the situation should be fixed.

The problem is that when Converter1 is used in this context the target type is System.Object. Now the BooleanAndConverter requires values of a certain type (Boolean), so how can I get that type passed as the target type of Converter1?

As requested here is the BooleanAndConverter code:

    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        foreach (object value in values)
        {
            if (value.GetType() != typeof(bool))
            {
                throw new ArgumentException("BooleanAndConverter can only be used to convert booleans."); // developer error
            }
        }

        if (targetType != typeof(bool))
        {
            throw new ArgumentException("BooleanAndConverter can only convert to a boolean."); // developer error
        }

        foreach (object value in values)
        {
            if ((bool)value == false)
            {
                return false;
            }
        }
        return true;
    }

Let me restate the question as there seems to be some confusion. Converter1 knows what type it can convert from and to. It throws an exception when called with the wrong types. In this situation the targetType is not getting specified and an exception is being thrown. How do I get the targetType specified correctly? When not used in a multi-binding situation is does always get specified correctly based on what is being converted.

Answer

Frederick picture Frederick · Jul 7, 2015

An possible alternative to some comments using a CommandParameter could be a MarkupExtension. Then you could write your MultiBinding like:

<MultiBinding Converter="{StaticResource BooleanAndConverter}">
  <Binding Path="Prop1" Converter="{conv:DebugTypeCheck, CheckType={x:Type sys:Boolean}" />
  <Binding Path="Prop2" Converter="{StaticResource DebugTypeCheckConverter}" CommandParameters="{x:Type sys:Boolean}" />
</MultiBinding>

On StackOverflow you can find several posts about Markupextension-Converters like here.

Sample implementation for both ways:

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

    public Type CheckType { get; set; }

    [Conditional("DEBUG")]
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value.GetType() != CheckType)
        {
            throw new ArgumentException(); // developer error
        }

        return value;
    }  

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    } 
}

public class DebugTypeCheckConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value.GetType() != (Type)parameter)
        {
            throw new ArgumentException(); // developer error
        }

        return value;
    }  

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    } 
}