Defining a Property in a IValueConverter class
Asked Answered
O

2

6

I need to define a DependencyProperty in a converter class because I need this data to make the conversion and this data is in another object, not the one I'm binding to.

My converter class is the following:

public class LEGOMaterialConverter   : DependencyObject, IValueConverter
{
    public DependencyProperty MaterialsListProperty = DependencyProperty.Register("MaterialsList", typeof(Dictionary<int, LEGOMaterial>), typeof(LEGOMaterialConverter));

    public Dictionary<int, LEGOMaterial> MaterialsList
    {
        get
        {
            return (Dictionary<int, LEGOMaterial>)GetValue(MaterialsListProperty);
        }
        set
        {
            SetValue(MaterialsListProperty, value);
        }
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        LEGOMaterial material = null;

        MaterialsList.TryGetValue((int)value, out material);

        return material;
    }

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

Then I'm instanciating it on the Window.REsources area:

<Window.Resources>
    <local:LEGOMaterialConverter x:Key="MaterialsConverter" MaterialsList="{Binding Path=Materials}" />
</Window.Resources>

I'm getting the following error:

   'MaterialsList' property was already registered by 'LEGOMaterialConverter'.

Does anyone have a clue on this error?

Oleaceous answered 25/1, 2015 at 21:33 Comment(1)
Have you tried using a multi-binding and a MultiValueConverter? See https://mcmap.net/q/134176/-binding-converterparameter.Abdul
J
9

Try doing it like this (just an example):

public class ValueConverterWithProperties : MarkupExtension, IValueConverter
{
    public int TrueValue { get; set; }

    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return this;
    }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if ((int) value == TrueValue)
        {
            return true;
        }
        return false;
    }

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

notice I derive from markup extension to allow me to use it like this:

<Window x:Class="Converter.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converter="clr-namespace:Converter"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <CheckBox IsChecked="{Binding item, Converter={converter:ValueConverterWithProperties TrueValue=5}}"></CheckBox>
    <CheckBox IsChecked="{Binding item2, Converter={converter:ValueConverterWithProperties TrueValue=10}}"></CheckBox>
</Grid>

Jarv answered 26/1, 2015 at 7:47 Comment(8)
Seems to solve my problem, but in your case, it's easy to pass the data, you type the integer value in the XAML. How would I pass a Dictionary to the converter?Oleaceous
whats in the dictionary? is it static? is it dynamic?Jarv
It's a property of one of my classes, it's loaded one time and after that it never changes anymore. But it's set only after the form is loaded...Oleaceous
If Its loaded one time and never changed, cant it be set to a static property of the converter?Jarv
Maybe, but since I can load the data only after the form is loaded, I have no idea how I could do this. If I set it as a static resource it would instantiate it when the XAML is being parsed, right?Oleaceous
Yes. but you can load it and then set a static property inside the converter. Also if its static, cant it be instantiated inside the converter statically?Jarv
I don't think I could instantiate it in the converter because this data is not exclusive for the converter. It's used in a lot of other parts of the code. But I think that I can load the data and then set property on the converter. I guess this must be done in code, and not XAML. I'll do some research and see if I can achieve results this way.Oleaceous
Is LegoMaterial an Enum?Jarv
G
4

Btw, this error is caused by your dependency property in the converter not being static (and after having created an instance of this converter somewhere before).

EDIT

So the problem is with this line:

public DependencyProperty MaterialsListProperty = DependencyProperty.Register("MaterialsList", typeof(Dictionary<int, LEGOMaterial>), typeof(LEGOMaterialConverter));

Here the Dependency Property MaterialsListProperty is being registered with every instantiation of an object of this type (i.e. LEGOMaterialConverter).

However Dependency Properties should be defined static, like so:

public static readonly DependencyProperty MaterialsListProperty = DependencyProperty.Register("MaterialsList", typeof(Dictionary<int, LEGOMaterial>), typeof(LEGOMaterialConverter));

A static variable is initialized (and the Dependency Property is registered) only once for all future instances of this type and that is what we need here. Failing to declare a Dependency Property as static results in the error from above.

Gazetteer answered 6/12, 2016 at 16:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.