The column background colour in my XamDataGrid keeps changing or to put it another way, beware the CellContainerGenerationMode when overriding the CellValuePresenterStyle.
What’s the problem ?
First off, please note I’m using v12.2 of Infragistics XamDataGrid, ofcourse this functionality may work differently in other versions of the control.
I’m still getting to grips with the Infragistics XamDataGrid. Whilst I know the old UltraGrid for WinForms pretty well, this is worthless experience when using the WPF XamDataGrid.
I was working on a way to highlight a “Reference” field/column in the XamDataGrid and got this working nicely using a Converter with a CellValuePresenterStyle but whilst playing with the UI I notice that horizontally scrolling the grid demonstrated a very strange behaviour. Initially my reference column was displayed with a gray background (my chosen colour) but when I scroll it out of view and back into view, it turned white (the default background). Worse still another column went gray. Not the sort of functionality a customer/user would want to see !
Let’s take a look at an example.
Note: this is a contrived example to demonstrate the issue, the code I was working on was more dynamic and the fields set-up in code behind, but I wanted to distill the example into it’s simplest components.
In this sample code I’m using a DataTable and a CellValuePresenterStyle (obviously this problem may not occur in different scenarios).
First up, let’s look at the sample data, we’re going to create enough columns to require us to horizontally scroll
var dataTable = new DataTable(); dataTable.Columns.Add("A1", typeof(int)); dataTable.Columns.Add("B1", typeof(int)); dataTable.Columns.Add("C1", typeof(int)); dataTable.Columns.Add("D1", typeof(int)); dataTable.Columns.Add("E1", typeof(int)); dataTable.Columns.Add("F1", typeof(int)); dataTable.Columns.Add("G1", typeof(int)); dataTable.Columns.Add("H1", typeof(int)); dataTable.Columns.Add("I1", typeof(int)); dataTable.Columns.Add("J1", typeof(int)); dataTable.Columns.Add("K1", typeof(int)); dataTable.Columns.Add("L1", typeof(int)); dataTable.Columns.Add("M1", typeof(int)); dataTable.Columns.Add("N1", typeof(int)); var row1 = dataTable.NewRow(); row1["A1"] = 1; row1["B1"] = 1; row1["C1"] = 1; row1["D1"] = 1; row1["E1"] = 1; row1["F1"] = 1; row1["G1"] = 1; row1["H1"] = 1; row1["I1"] = 1; row1["J1"] = 1; row1["K1"] = 1; row1["L1"] = 1; row1["M1"] = 1; row1["N1"] = 1; dataTable.Rows.Add(row1); var row2 = dataTable.NewRow(); row2["A1"] = 2; row2["B1"] = 2; row2["C1"] = 2; row2["D1"] = 2; row2["E1"] = 2; row2["F1"] = 2; row2["G1"] = 2; row2["H1"] = 2; row2["I1"] = 2; row2["J1"] = 2; row2["K1"] = 2; row2["L1"] = 2; row2["M1"] = 2; row2["N1"] = 2; dataTable.Rows.Add(row2); DataContext = dataTable;
Next up, let’s look at the XAML for the XamDataGrid
<igDP:XamDataGrid DataSource="{Binding}" > <igDP:XamDataGrid.FieldLayouts> <igDP:FieldLayout> <igDP:FieldLayout.Fields> <igDP:Field Name="A1" Label="A1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="B1" Label="B1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="B1" Label="B1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="C1" Label="C1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="D1" Label="D1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="E1" Label="E1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="F1" Label="F1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="G1" Label="G1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="G1" Label="G1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="H1" Label="H1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="I1" Label="I1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="J1" Label="J1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="K1" Label="K1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="L1" Label="L1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="M1" Label="M1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> <igDP:Field Name="N1" Label="N1"> <igDP:Field.Settings> <igDP:FieldSettings CellValuePresenterStyle="{StaticResource CellValuePresenterStyle}"/> </igDP:Field.Settings> </igDP:Field> </igDP:FieldLayout.Fields> </igDP:FieldLayout> </igDP:XamDataGrid.FieldLayouts> </igDP:XamDataGrid>
Next let’s look at style
<Style TargetType="{x:Type igDP:CellValuePresenter}" x:Key="CellValuePresenterStyle"> <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource BackgroundConverter}}" /> </Style>
and finally the converter
public class BackgroundConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var cellValuePresenter = value as CellValuePresenter; if (cellValuePresenter != null) { // in my code this is "discovered" at runtime, but you get the idea if (cellValuePresenter.Field.Name == "E1") return Brushes.Gray; } return Binding.DoNothing; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
Now if you run up an example WPF Window with these parts and horizontally scroll you should see the gray background column switch from the E1 column to other columns.
A solution
So I had a chat with a colleague who mentioned the grid’s virtualization options being a possible issue – lo and behold adding the CellContainerGenerationMode attribute and setting it to LazyLoad worked.
For example
<igDP:XamDataGrid DataSource="{Binding DefaultView}" CellContainerGenerationMode="LazyLoad">
It appears the XamDataGrid has a default value of Recycle for the CellContainerGenerationMode and an educated guess (based as much on the naming as anything) suggests this means the XamDataGrid is reusing the field/column when scrolling – this is all well and good when your column styling is static, but not so good when you have something a little more dynamic.
References
Although not talking about this specific issue, it’s worth noting this post of performance and optimization within the XamDataGrid – Optimizing Infragistics XamDataGrid Performance.