views:

257

answers:

2

I have bound a flagged enum to a bunch of checkboxes by using a value converter that works as described in the solution to this question. This works fine when I'm working with a flag that hasn't been set to anything.

However, in the non-trivial use case that the flag is actually set to some data, on load the checkboxes are bound correctly to the enum field. However, when I check/uncheck the box, it seems this binding has been lost.

For example, my enum and value converters are as follows:

[Flags]
enum Fruits : int { Apple = 1, Orange = 2, Peach = 4, None = 0 };

public Converter : IValueConverter
{
    private Fruits target;

    public Converter() { }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        Fruits mask = (Fruits)parameter;
        this.target = (Fruits)value;
        return ((mask & this.target) != 0);
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        this.target ^= (Fruits)parameter;
        return this.target;
    }
}

My XAML (in a datagrid) is as follows:

<toolkit:DataGrid.Columns>
    <toolkit:DataGridTemplateColumn Header="Fruits">
        <toolkit:DataGridTemplateColumn.CellTemplate>
            <DataTemplate>
                <DataTemplate.Resources>
                    <ui:Converter x:Key="Converter" />
                </DataTemplate.Resources>
                <StackPanel>
                    <CheckBox Content="Apple" IsChecked="{Binding Path=Fruits, Converter={StaticResource Converter}, ConverterParameter={x:Static constants:Fruits.Apple}}" />
                    <CheckBox Content="Orange" IsChecked="{Binding Path=Fruits, Converter={StaticResource Converter}, ConverterParameter={x:Static constants:Fruits.Orange}}" />
                    <CheckBox Content="Peach" IsChecked="{Binding Path=Fruits, Converter={StaticResource Converter}, ConverterParameter={x:Static constants:Fruits.Peach}}" />
                </StackPanel>
            </DataTemplate>
        </toolkit:DataGridTemplateColumn.CellTemplate>
    </toolkit:DataGridTemplateColumn>
</toolkit:DataGrid.Columns>

When I load the binding from the object, it goes through Convert for each item in the list (an ObservableCollection) and binds the checkboxes correctly, and stores them in the target field. However, when I check/uncheck another box, the target field is defaulted to "None" and the behavior is as if you're starting over from scratch.

Any help?

+1  A: 

I might be off-base here, but could it be because your enum defines "Three" as 3?

Since you're using bitwise operators to check and uncheck the checkboxes, the "Three" value (0x11) will correspond to both the "One" and "Two" values (0x01 and 0x10 respectively).

I know it seems counter-intuitive, but try changing your enum declaration to:

enum Numbers : int { One = 1, Two = 2, Three = 4, None = 0 };
Matt Hamilton
My bad. I rewrote the original code since I didn't want to share it. There are actually 16 enums and they are all powers of 2. Sorry about that!
sohum
I think the issue may be that the IValueConverter is getting reinitialized for some reason. How could I go about checking this?
sohum
I can't imagine it would be, but I suppose you could create a parameterless constructor and put a breakpoint in it test your theory.
Matt Hamilton
+2  A: 

Where is the "Converter" resource defined? At what scope? It would have to be defined at the scope of your items template if you've got a list of items because it needs to maintain state for each item individually.

Drew Marsh
Ooh +1 that makes sense.
Matt Hamilton
Hope that's it and it solves the problem for you. ;)
Drew Marsh
It's defined in the DataTemplate.Resources section of the DataGridTemplateColumn. Is that the same thing? I'll update the question with the code.
sohum
I have updated the code. Like I said, the binding does work on the first time through. However, once I close and restart the application and load the bindings from the database, it binds them correctly on load but seems to lose these values after that.
sohum
Hmm... ya know what, I forget off the top of my head whether or not the resources for a template are shared amongst instances and I don't have time to test right this second. Can you try moving the converter into the resources of the <StackPanel> instead really quick???
Drew Marsh
genius... works like a charm!
sohum
Great, glad we could figure it out!
Drew Marsh