Binding a DataTrigger to the IsChecked property of a checkbox

WPFNewbie Wannabe picture WPFNewbie Wannabe · Mar 28, 2012 · Viewed 8.1k times · Source

I believe what I'm trying to do is "simple" enough, so I'm probably just missing something obvious.

In a DataGrid, I am trying to bind a CheckBox so that when it is checked, the Background color of its row will change. Every row has a CheckBox. I am basically implementing my own select-multiple-rows functionality (it's a product requirement, don't ask), and I have everything else working but this visual indication of a selected row.

I've read this question but where I lack my answer is what exactly to put as "BooleanPropertyOnObjectBoundToRow". I've also looked at this question and tried messing with a RelativeSource but with no luck.

I create my grid in my code-behind, but here is my current style used for rows (which has my DataTrigger defined):

<Style x:Key="MyRowStyle" TargetType="DataGridRow">
      <Style.Triggers>
           <DataTrigger Binding="{Binding IsChecked}" Value="True">
               <Setter Property="Background" Value="Blue"/>
           </DataTrigger>
      </Style.Triggers>
</Style>

Now in my code-behind, I create my DataGridTemplateColumn and use a Factory to create my checkboxes, and here is my Binding-relevant code:

Binding checkBinding = new Binding("IsChecked");
checkBinding.Mode = BindingMode.OneWayToSource;
RelativeSource relativeSource = new RelativeSource();
relativeSource.AncestorType = typeof(DataGridRow);
relativeSource.Mode = RelativeSourceMode.FindAncestor;
checkBinding.RelativeSource = relativeSource;
factory.SetBinding(CheckBox.IsCheckedProperty, checkBinding);

What may be of interest is the fact that I set the ItemsSource of my DataGrid to a DataTable, but my CheckBox column does NOT have a corresponding column in the DataTable. I simply add the template column separately, maybe this lack of underlying storage is affecting this?

In any case if you need any more info, please let me know. Thanks!

Answer

Phil picture Phil · Mar 31, 2012

Here's an example that works for me using C# classes, not a DataSet.

Xaml

<Page.Resources>
    <Style x:Key="RowStyle" TargetType="{x:Type DataGridRow}">
        <Style.Triggers>
            <DataTrigger Binding="{Binding IsChecked, UpdateSourceTrigger=PropertyChanged}" Value="True">
                <Setter Property="Background" Value="Blue"/>
            </DataTrigger>
        </Style.Triggers>
    </Style>
</Page.Resources>

<Page.DataContext>
    <Samples:DataGridRowHighlightViewModels/>
</Page.DataContext>

<Grid>
    <DataGrid ItemsSource="{Binding Items}" RowStyle="{StaticResource RowStyle}" CanUserAddRows="False" AutoGenerateColumns="False">
        <DataGrid.Columns>
            <DataGridCheckBoxColumn Header="Selected" Binding="{Binding IsChecked}"/>
            <DataGridTextColumn Header="Name" Binding="{Binding Name}"/>
        </DataGrid.Columns>
    </DataGrid>
</Grid>

C#

public class DataGridRowHighlightViewModels
{
    public DataGridRowHighlightViewModels()
    {
        Items = new List<DataGridRowHighlightViewModel>
                    {
                        new DataGridRowHighlightViewModel {Name = "one"},
                        new DataGridRowHighlightViewModel {Name = "two"},
                        new DataGridRowHighlightViewModel {Name = "three"},
                        new DataGridRowHighlightViewModel {Name = "four"},
                    };
    }
    public IEnumerable<DataGridRowHighlightViewModel> Items { get; set; } 
}

// ViewModelBase and Set() give INotifyPropertyChanged support (from MVVM Light)
public class DataGridRowHighlightViewModel : ViewModelBase 
{
    private bool _isChecked;
    public bool IsChecked
    {
        get { return _isChecked; }
        set { Set(()=>IsChecked, ref _isChecked, value); }
    }

    private string _name;
    public string Name
    {
        get { return _name; }
        set { Set(()=>Name, ref _name, value); }
    }
}