Search code examples
c#wpfbindingdatagriddatatrigger

How to color Expander in a DataGrid based on a DataTrigger?


I have a problem with coloring my Expander in the DataGrid based on a DataTrigger. I have tried many things and red many threads, but without luck.

I want the color to change based on the boolean that are in the ItemsSource.

Below it the code that set the ItemsSource:

private void SetDataGrid(ObservableCollection<SourceInfo> myinfoList)
{
   var ColectList = new ListCollectionView(myinfoList);
   ColectList.GroupDescriptions.Add(new PropertyGroupDescription("DrawNr"));

   MyDataGrid.ItemsSource = ColectList;
}

Below is my XAML (the check is my parameter in the class that is the itemsource):

<DataGrid ItemsSource="{Binding}"
          Name="MyDataGrid"
          Margin="244,10,20,7"
          AutoGenerateColumns="True"
          CanUserAddRows="False"
          RowEditEnding="MyDataGrid_RowEditEnding"
          Loaded="MyDataGrid_Loaded"
          BorderBrush="{x:Null}"
          Background="{x:Null}"
          HorizontalGridLinesBrush="#FF646464"
          VerticalGridLinesBrush="#FF646464"
          FontFamily="Open Sans">
   <DataGrid.GroupStyle>
      <GroupStyle>
         <GroupStyle.ContainerStyle>
            <Style TargetType="{x:Type GroupItem}">
               <Setter Property="Margin"
                       Value="0,0,0,5" />
               <Setter Property="Template">
                  <Setter.Value>
                     <ControlTemplate TargetType="{x:Type GroupItem}">
                        <Expander IsExpanded="False"
                                  BorderBrush="#FF002255"
                                  Foreground="Black"
                                  BorderThickness="1,1,1,5">
                           <Expander.Style>
                              <Style TargetType="{x:Type Expander}">
                                 <Setter Property="Background"
                                         Value="Red" />
                                 <Style.Triggers>
                                    <DataTrigger Binding="{Binding Path=check, RelativeSource={RelativeSource self}}"
                                                 Value="True">
                                       <Setter Property="Background"
                                               Value="Green" />
                                    </DataTrigger>
                                 </Style.Triggers>
                              </Style>
                           </Expander.Style>
                           <Expander.Header>
                              <StackPanel>
                                 <StackPanel Orientation="Horizontal">
                                    <TextBlock Text="{Binding DrawNr}" />
                                    <TextBlock Text="{Binding ItemCount, StringFormat=Count: {0}}"
                                               Margin="30,0,0,0" />
                                 </StackPanel>
                              </StackPanel>
                           </Expander.Header>
                           <Expander.Content>
                              <ItemsPresenter />
                           </Expander.Content>
                        </Expander>
                     </ControlTemplate>
                  </Setter.Value>
               </Setter>
            </Style>
         </GroupStyle.ContainerStyle>
      </GroupStyle>
   </DataGrid.GroupStyle>
</DataGrid>

The DataGrid:

Screenshot of the DataGrid.


Solution

  • When you group a collection view, the data context of a group is a CollectionViewGroup. It exposes several properties, like the ItemCount or Name, which is the value of the property that you grouped by for the current group. Consequently, if you want to bind the Expander header to DrawNr, use Name.

    <Expander.Header>
       <StackPanel>
          <StackPanel Orientation="Horizontal">
             <TextBlock Text="{Binding Name}" />
             <TextBlock Margin="30,0,0,0" Text="{Binding ItemCount, StringFormat=Count: {0}}" />
          </StackPanel>
       </StackPanel>
    </Expander.Header>
    

    As for the check property, a group can contain multiple items, so the check property of which item exactly should be considered in the DataTrigger, the first, a boolean And of all items, anything else?

    Here, I check if there is exactly one item in the group and use its check property. If it is True, the Expander background will be green. In all other cases (also for more than one item), it will be red.

    <Expander.Style>
       <Style TargetType="{x:Type Expander}">
          <Setter Property="Background" Value="Red" />
          <Style.Triggers>
             <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                   <Condition Binding="{Binding Items.Count}" Value="1" />
                   <Condition Binding="{Binding Items[0].Check}" Value="True" />
                </MultiDataTrigger.Conditions>
                <Setter Property="Background" Value="Green" />
             </MultiDataTrigger>
          </Style.Triggers>
       </Style>
    </Expander.Style>
    

    As a general note, the widely accepted convention for property names is Pascal-Case, e.g. Check.