views:

122

answers:

2

There is a relatively simple thing I'm trying to achieve but I'm unsure how to do it. Basically, I have a CLR class as follows:

class SomeClass
{
    public SomeEnum Status;
}

public enum SomeEnum { One, Two, Three };

I've got a DataGrid that I'm binding an ObservableCollection<SomeClass> programmatically through the code-behind. In this DataGrid I have a DataGridTemplateColumn containing two buttons, as follows:

<toolkit:DataGridTemplateColumn Header="Actions">
    <toolkit:DataGridTemplateColumn.CellTemplate>
    <DataTemplate>
    <StackPanel Orientation="Horizontal">
        <Button Content="ActionOne" />
        <Button Content="ActionTwo" />
    </StackPanel>
    </DataTemplate>
</toolkit:DataGridTemplateColumn.CellTemplate>
</toolkit:DataGridTemplateColumn>

What I want to do is bind the IsEnabled property of these buttons to a comparison based on the value of {Binding Path=Status}. For example, in pseudocode:

ActionOne.IsEnabled = BoundValue.Status != SomeEnum.Two
ActionTwo.IsEnabled = BoundValue.Status == SomeEnum.One || BoundValue.Status == SomeEnum.Two

Is there anyway to do this in XAML? The alternative would be just to write a value converter for each button, but since the content and other details of the button may vary, too, I don't want to end up writing like 6 value converters.

Cheers!

+2  A: 

You could do this using a DataTrigger in conjunction with a Converter like below. However, Bryan's solution has the benefit of not using multiple converters and it looks like that was one of your concerns so his answer might be better for your scenario.

<Button>
    ....
    <Button.Style>
        <Style TargetType="{x:Type Button}">
            <Setter Property="IsEnabled" Value="False" />
            <Style.Triggers>
                <DataTrigger Binding="{Binding Path=Status, Converter={StaticResource yourConverter}}" Value="True">
                    <Setter Property="IsEnabled" Value="True" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Button.Style>

Another option would be to not use the DataTrigger and add the binding directly in the IsEnabled property:

<Button  
    IsEnabled="{Binding Path=Status, Converter={StaticResource yourConverter}}"  
    ...  
/> 
Taylor Leese
+2  A: 

Why not expose additional Properties in SomeClass that performs the comparison logic?

ex:

public bool ActionOneEnabled
{
    get { return Status != SomeEnum.Two; }
}

Then you can easily bind the Button's IsEnabled to the appropriate Property.

Don't forget to include an OnPropertyChanged("ActionOneEnabled") in your setter for Status - so that when your Status changes your Properties based on Status are re-evaluated.

Bryan Batchelder
Yes, this is the MVVM idiom.
itowlson
I was toying with this. While it would definitely work and have the least amount of code, at the same time it is including UI information within my object. For example, if I want to make the content of the button depend on Status, I would have to put that information into my SomeClass properties, whereas that should really be somewhere in the View classes/XAML
sohum
If that is a concern to you then you'll probably need to use the converter method I proposed.
Taylor Leese
How about creating SomeClassViewModel which wraps SomeClass and has those Properties defined? SomeClass then stays ignorant of UI concerns. Though at that point it is unclear if this is superior to type converters. My guess is that the class wrapping would be more "blendable", if that is a concern for you.
Bryan Batchelder
Bryan, I like that solution. I'd prefer the class wrapping to the converters.
sohum