Xaphann
Xaphann

Reputation: 3677

IValueConverter and binding a DependencyObject

I have a ComboBox that I need to do a converter on the SelectedItem. Problem is the IValueConverter needs the binding value but a Collection as well. Configured a DependencyObject but it is giving me an error message of

Object of type 'System.Windows.Data.Binding' cannot be converted to type 'System.Collections.ObjectModel.ObservableCollection`1[MyClass]'.

Here is my IValueConverter

public class MyConverter : DependencyObject, IValueConverter
{
    public static readonly DependencyProperty FoldersProperty = 
        DependencyProperty.Register(nameof(MyCollection), typeof(ObservableCollection<MyClass>), typeof(MyClassModelToMyClassID), new FrameworkPropertyMetadata(new ObservableCollection<MyClass>()));
    public ObservableCollection<MyClass> MyCollection
    {
        get { return GetValue(FoldersProperty) as ObservableCollection<MyClass>; }
        set { SetValue(FoldersProperty, value); }
    }
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        //Amazing Convert code that uses MyCollection and Value
    }
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        //Amazing ConvertBack code that uses MyCollection and Value
    }
}

Here is how I am calling it:

<Page.Resources>
    <converter:MyConverter x:Key="Converter" MyCollection="{Binding DataCollection}" />
</Page.Resources>
....
<ComboBox 
    ItemsSource="{Binding DataCollection}"
    SelectedItem="{Binding Path=MyValue, Converter={StaticResource TaxCodeConverter}}" />

edit: added the full IValueConvert subtracted the Convert and ConvertBack code

Upvotes: 2

Views: 521

Answers (1)

Like a BindingProxy, it needs to be a Freezable. Also, don't pass a new observable collection to your metatadata. That's a reference type, so all instances of this converter will be initialized with the same actual collection instance.

Let me know if you run into some other issue, but I've done this and been able to bind to the dependency property.

Many would argue that a better approach would be a multibinding and a multi-value converter. I think there's value in having a strongly typed property with a descriptive name.

public class MyConverter : Freezable, IValueConverter
{
    /* omitted: Convert() and ConvertBack() */

    public MyConverter()
    {
        //  Initialize here if you need to
        MyCollection = new ObservableCollection<MyClass>();
    }

    protected override Freezable CreateInstanceCore()
    {
        return new MyConverter();
    }

    public static readonly DependencyProperty MyCollectionProperty =
        DependencyProperty.Register(nameof(MyCollection), 
            typeof(ObservableCollection<MyClass>), typeof(MyConverter),
            new FrameworkPropertyMetadata(null));

    public ObservableCollection<MyClass> MyCollection
    {
        get { return GetValue(MyCollectionProperty) as ObservableCollection<MyClass>; }
        set { SetValue(MyCollectionProperty, value); }
    }
}

XAML usage will be just as you have it in your question: Bind the dependency property, and the binding will update that property of that instance of MyConverter, provided that your Page's DataContext has an appropriately typed property named DataCollection.

<Page.Resources>
    <converter:MyConverter x:Key="Converter" MyCollection="{Binding DataCollection}" />
</Page.Resources>

Upvotes: 2

Related Questions