Dennis February 2016

Workaround to avoid "Cannot create default converter to perform 'two-way' conversions between types 'Derived_N' and 'Base'" error

I have some types hierarchy:

public class Base {}
public class Derived_1 : Base {}
public class Derived_2 : Base {}
// more descendants...
public class Derived_N : Base {}

Types from this hierarchy are used as lookup lists in view models:

public class SomeViewModel
{
    // available items
    public IEnumerable<Derived_N> SomeItems { get; }

    // currently selected item
    public Derived_N SelectedItem { get; set; }

    // there could be several property pairs as above
}

To select values from lookup list I've created user control (some sort of selector). Since from the point of selection process all Base descendants looks similar, user control operates Base type properties:

    public IEnumerable<Base> ItemsSource
    {
        get { return (IEnumerable<Base>)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }

    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register("ItemsSource", typeof(IEnumerable<Base>), typeof(BaseSelector), new PropertyMetadata(null));

    public Base SelectedItem
    {
        get { return (Base)GetValue(SelectedItemProperty); }
        set { SetValue(SelectedItemProperty, value); }
    }

    public static readonly DependencyProperty SelectedItemProperty =
        DependencyProperty.Register("SelectedItem", typeof(Base), typeof(BaseSelector), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

XAML usually looks like:

<myCtrls:BaseSelector ItemsSource="{Binding SomeItems}"
                      SelectedItem="{Binding SelectedItem}"/>

This works as expected, but there are binding errors like this:

Cannot create default converter to perform 'two-way' conversions between types 'Derived_N' and 'Ba

Answers


Dennis February 2016

For now, I've solved a problem with replacing property type for user control's properties to IEnumerable / object respectively (IEnumerable<object> / object is also a solution):

    public static readonly DependencyProperty ItemsSourceProperty =
        DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(BaseSelector), new PropertyMetadata(null));

    public static readonly DependencyProperty SelectedItemProperty =
        DependencyProperty.Register("SelectedItem", typeof(object), typeof(BaseSelector), new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));

This leads to extra type checking inside user control, but doesn't generate any binding errors (and I really don't understand, why - the case with object is the same as with Base, IMO).


Kylo Ren February 2016

use TypeConverter with your classes to avoid this error:

[TypeConverter(typeof(MyConverter))]
public class Derived_N : Base
{
}

TypeConverter:

public class MyConverter: TypeConverter
{
    public override bool CanConvertFrom(ITypeDescriptorContext context, 
    Type sourceType)
    {
        return sourceType == typeof(Base);
    }

public override object ConvertFrom(ITypeDescriptorContext context,
    System.Globalization.CultureInfo culture, object value)
    {
        return value as Base;
    }

public override bool CanConvertTo(ITypeDescriptorContext context, 
    Type destinationType)
    {
        return destinationType == typeof(Base);
    }

public override object ConvertTo(ITypeDescriptorContext context,
    System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        return value == null ? null : value as Base;
    }
}

PS: please change the above code as your need. I just wrote the minimal to prevent error.

Post Status

Asked in February 2016
Viewed 1,646 times
Voted 12
Answered 2 times

Search




Leave an answer