5

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?

Luke Woodward
  • 63,336
  • 16
  • 89
  • 104
rbasniak
  • 4,484
  • 11
  • 51
  • 100
  • 1
    Have you tried using a multi-binding and a MultiValueConverter? See http://stackoverflow.com/questions/15309008/binding-converterparameter. – Luke Woodward Jan 25 '15 at 21:44

2 Answers2

8

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>

Amit Raz
  • 5,370
  • 8
  • 36
  • 63
  • 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? – rbasniak Jan 26 '15 at 12:20
  • whats in the dictionary? is it static? is it dynamic? – Amit Raz Jan 26 '15 at 12:23
  • 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... – rbasniak Jan 26 '15 at 12:26
  • 1
    If Its loaded one time and never changed, cant it be set to a static property of the converter? – Amit Raz Jan 26 '15 at 12:37
  • 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? – rbasniak Jan 26 '15 at 13:29
  • 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? – Amit Raz Jan 26 '15 at 13:30
  • 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. – rbasniak Jan 26 '15 at 13:34
  • Is LegoMaterial an Enum? – Amit Raz Jan 26 '15 at 13:39
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.

Tom Ladek
  • 688
  • 11
  • 19