Search code examples
c#wpfmaterial-designwpfdatagrid

How do I Inherit a WPF DataGrid Cell Style when programmatically adding a DataTrigger?


I'm writing a WPF application which makes use of the DataGrid control. I'm using the MaterialDesign theme to style the application and this gives a nice look and feel.

However for complex reasons I wont go into here I'm required to add the columns into the dataGrid programmatically. For some of the columns I'm also styling the columns to highlight pass / fail in red. When I do this I loose 'some of the styling' provided by material design for that columns. Namely the Horizontal and Vertical alignment.

DataGrid showing the third column alignment is not being picked up

The code to the above is as follows:

            // Define Setter
            Setter setterResultFail = new Setter();
            setterResultFail.Property = DataGridCell.BackgroundProperty;
            setterResultFail.Value = Brushes.Red;

            // Create a column for the Site.
            var currentColumn = new DataGridTextColumn();
            currentColumn.Header = "Device #";
            currentColumn.Binding = new Binding("Device");
            ResultsDataGrid.Columns.Add(currentColumn);

            // Create a column for the Site.
            currentColumn = new DataGridTextColumn();
            currentColumn.Header = "Site";
            currentColumn.Binding = new Binding("Site");
            ResultsDataGrid.Columns.Add(currentColumn);

            // Create a column for the Pass Fail.
            currentColumn = new DataGridTextColumn();
            currentColumn.Header = "Pass Fail";
            currentColumn.Binding = new Binding("PassFail") { Converter = new BooleanToPassFailConverter() };

            // Create cellstyle to make the cell 'red' when the PassFail value is False. ( this is done via a data trigger )
            cellStyle = new Style(typeof(DataGridCell));

            // Define First DataTrigger that sets a CELL red if the value is a fail.
            dataTrigger = new DataTrigger();
            dataTrigger.Value = "False";
            dataTrigger.Binding = new Binding("PassFail");            
            dataTrigger.Setters.Add(setterResultFail);

            // Add the data-triggers to the cell style.
            cellStyle.Triggers.Clear();
            cellStyle.Triggers.Add(dataTrigger);

            // Apply the newly created cell style.
            currentColumn.CellStyle = cellStyle;

            ResultsDataGrid.Columns.Add(currentColumn);

Clearly the new cellStyle is used instead of the MaterialDesign style. I've tried setting the values for vertical / horizontal manually but I can't get it to look correct:

            Setter setterTextContentHorizonalAlignment = new Setter();
            setterTextContentHorizonalAlignment.Property = DataGridCell.HorizontalContentAlignmentProperty;
            setterTextContentHorizonalAlignment.Value = HorizontalAlignment.Center;

            Setter setterTextContentVerticalAlignment = new Setter();
            setterTextContentVerticalAlignment.Property = DataGridCell.VerticalContentAlignmentProperty;
            setterTextContentVerticalAlignment.Value = VerticalAlignment.Center;

            Setter setterTextHorizontalAlignment = new Setter();
            setterTextHorizontalAlignment.Property = DataGridCell.HorizontalAlignmentProperty;
            setterTextHorizontalAlignment.Value = HorizontalAlignment.Center;

            Setter setterTextVerticalAlignment = new Setter();
            setterTextVerticalAlignment.Property = DataGridCell.VerticalAlignmentProperty;
            setterTextVerticalAlignment.Value = VerticalAlignment.Center;

            cellStyle.Setters.Add(setterTextContentHorizonalAlignment);
            cellStyle.Setters.Add(setterTextContentVerticalAlignment);
            cellStyle.Setters.Add(setterTextHorizontalAlignment);
            cellStyle.Setters.Add(setterTextVerticalAlignment);

Is there a way I can add to the style rather than replace it...similar to the BasedOn approch in XAML?


Solution

  • After much wasting of time on this question I came across Danny Beckett's similar question and King King's answer. By using his answer and applying it to the specific cell I was having trouble with it fixed the issue:King King's answer

         // Create a column for the Pass Fail.
         currentColumn = new DataGridTextColumn();
         currentColumn.Header = "Pass Fail";
         currentColumn.Binding = new Binding("PassFail") { Converter = new BooleanToPassFailConverter() };
    
         // Create cellstyle to make the cell 'red' when the PassFail value is False. ( this is done via a data trigger )
         cellStyle = new Style(typeof(DataGridCell));
    
         // Define First DataTrigger that sets a CELL red if the value is a fail.
         dataTrigger = new DataTrigger();
         dataTrigger.Value = "False";
         dataTrigger.Binding = new Binding("PassFail");
         dataTrigger.Setters.Add(setterResultFail);
    
         // Add the data-triggers to the cell style.
         cellStyle.Triggers.Clear();
         cellStyle.Triggers.Add(dataTrigger);
    
         //root visual of the ControlTemplate for DataGridCell is a Border
         var border = new FrameworkElementFactory(typeof(Border));
         border.SetBinding(Border.BorderBrushProperty, new Binding("BorderBrush")
         {
               RelativeSource = RelativeSource.TemplatedParent
         });
    
         border.SetBinding(Border.BackgroundProperty, new Binding("Background") { RelativeSource = RelativeSource.TemplatedParent });
         border.SetBinding(Border.BorderThicknessProperty, new Binding("BorderThickness") { RelativeSource = RelativeSource.TemplatedParent });
         border.SetValue(SnapsToDevicePixelsProperty, true);
    
         //the only child visual of the border is the ContentPresenter
         var contentPresenter = new FrameworkElementFactory(typeof(ContentPresenter));
         contentPresenter.SetBinding(SnapsToDevicePixelsProperty, new Binding("SnapsToDevicePixelsProperty") { RelativeSource = RelativeSource.TemplatedParent });
         contentPresenter.SetBinding(VerticalAlignmentProperty, new Binding("VerticalContentAlignment") { RelativeSource = RelativeSource.TemplatedParent });
         contentPresenter.SetBinding(HorizontalAlignmentProperty, new Binding("HorizontalContentAlignment") { RelativeSource = RelativeSource.TemplatedParent });
         //add the child visual to the root visual
         border.AppendChild(contentPresenter);
    
         //here is the instance of ControlTemplate for DataGridCell
         var template = new ControlTemplate(typeof(DataGridCell));
         template.VisualTree = border;
    
         //define the style
         cellStyle.Setters.Add(new Setter(TemplateProperty, template));
         cellStyle.Setters.Add(new Setter(VerticalContentAlignmentProperty, VerticalAlignment.Center));
         cellStyle.Setters.Add(new Setter(HorizontalContentAlignmentProperty, HorizontalAlignment.Center));
    
         // Apply the newly created cell style.
         currentColumn.CellStyle = cellStyle;