Workaround to avoid "It is not possible to create a default converter to perform" two-way "conversions between the types" Derived_N "and" Base "

I have a type 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 search lists in models of the form:

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 the search list, I created a user control (some kind of selector). Since all descendants Baselook the same from the selection process , user control controls properties of the type Base:

    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 this:

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

This works as expected, but there are such errors:

Unable to create default converter for two-way conversions between types "Derived_N" and "Base"

, - SelectedItem , Base, . , ​​ :

public class DummyConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value;
    }

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

:

<myCtrls:BaseSelector ItemsSource="{Binding SomeItems}"
                      SelectedItem="{Binding SelectedItem, Converter={StaticResource DummyConverterKey}}"/>

- , ( ).

?

+4
2

IEnumerable/object (IEnumerable<object>/object ):

    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));

, ( , - object Base, IMO).

+1

TypeConverter , :

[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:, , . , .

0

Source: https://habr.com/ru/post/1627763/


All Articles