Patrick Patrick - 9 days ago 6
C# Question

Datagrid acting weirdly when scrolling




EDIT : I have been led to notice that the problem is not on the first line but all lines are shifted after mouse scrolling.




I am perfectly aware that this is a tricky problem which might lead me to an incomplete or too personal question. That said I'll try to explain it as clearly as possible.
I have a datagrid which is build by me through a routine. If necessary I can share it. After that the datagrid undergoes transformations through events:

<DataGrid Name="dtgResults" Background="Transparent" CanUserSortColumns="False" IsReadOnly="True" Foreground="Black" LoadingRow="Datagrid_LoadingRow">
<DataGrid.Resources>
<Style TargetType="DataGridCell">
<EventSetter Event="DataGridCell.Loaded" Handler="DataGridCell_Load"/>
<Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource AncestorType=DataGrid}}"/>
<Setter Property="HorizontalAlignment" Value="Right" />
</Style>
</DataGrid.Resources>
</DataGrid>


that is:




in Datagrid_LoadingRow

int index = row.GetIndex();
if (obcMyDim[index].IsComment) <-----a matrix telling when it's a comment
row.Foreground = new SolidColorBrush(Colors.White);
else
row.Foreground = new SolidColorBrush(Colors.Black);


so it's just a colouring matter no cell data change!




in DataGridCell_Load instead i format the number of decimals and make through this:

DataGridCell cell = sender as DataGridCell;
DataGrid parentDataGrid = (DataGrid)(cell.Tag);

int column = cell.Column.DisplayIndex;// da 0
int row = -1;
//I get the line
DependencyObject rowDO = cell as DependencyObject;
while (rowDO != null && !(rowDO is DataGridRow))
rowDO = VisualTreeHelper.GetParent(rowDO);
if (rowDO != null)
{
DataGridRow gridrow = (DataGridRow)rowDO;
row = gridrow.GetIndex();
}


...

string strCellContent = ((TextBlock)cell.Content).Text;
if (strCellContent.Trim() != string.Empty)
{
if (strCellContent.IsNumeric())<----custom function
{
dVal = double.Parse(strCellContent, CultureInfo.InvariantCulture);
((TextBlock)cell.Content).Text = dVal.ToString("0.0000");

bool condOutOfTolerance = ...;
//Errore
if (column >= 5 && condOutOfTolerance)
cell.Foreground = new SolidColorBrush(Colors.Red);
}
}


So in short the problem is that the FIRST LINE behaves weirdly after having

This is the first and correct image.
enter image description here

then after having scrolled up/down the datagrid the first line changes

enter image description here

and then again differently

enter image description here

I get the feeling that somehow it's a matter of refresh but I can't understand how to fix that.

Thank you for any help

Patrick
----ADD----

Here is how I manually populate my datagrid:

public void SynchronizeDtgResults(DataGrid dtg)
{
/*-----------------------------------------------*
* manuale generation HEADER / COLUMNS / ROWS *
*-----------------------------------------------*/
if (obcMyDim == null || obcMyDim.Count() == 0 || obcMyDim[0].obcItemsName == null || obcMyDim[0].obcItemsName.Count() == 0)
{
Serializers.Logger.WriteLog("WARNING SynchronizeDtgResults called with obcmMyDim not valid");
return;
}

int numColonneFisse = 5; //Num, name, nominal, ut, ul
int numParts = obcMyDim[0].obcItemsName.Count();//refer to the first coz are all the same
int numTotaleColonne = numColonneFisse + numParts;
int numTotaleRighe = obcMyDim.Count;
string[] columnLabels = new string[numTotaleColonne];

//1. Header Preparation
// first 5 fixed col
columnLabels[0] = Languages.Word(eWords.Num);
columnLabels[1] = Languages.Word(eWords.Name);
columnLabels[2] = Languages.Word(eWords.Nominal);
columnLabels[3] = Languages.Word(eWords.UT);
columnLabels[4] = Languages.Word(eWords.LT);
// and then the names of the parts
for (int iii = 0; iii < numParts; iii++)
columnLabels[iii + numColonneFisse] = obcMyDim[0].obcItemsName[iii];

//2. Clean and add header
Application.Current.Dispatcher.Invoke((Action)(() => { dtg.Columns.Clear(); }));
Application.Current.Dispatcher.Invoke((Action)(() => { dtg.Items.Clear(); }));

var styleHeaderDatagrid = new Style(typeof(System.Windows.Controls.Primitives.DataGridColumnHeader));
styleHeaderDatagrid.Setters.Add(new Setter { Property = BorderBrushProperty, Value = Brushes.Black });
styleHeaderDatagrid.Setters.Add(new Setter { Property = BorderThicknessProperty, Value = new Thickness(1) });
styleHeaderDatagrid.Setters.Add(new Setter { Property = ForegroundProperty, Value = Brushes.Black });
styleHeaderDatagrid.Setters.Add(new Setter { Property = FontWeightProperty, Value = FontWeights.Bold });
styleHeaderDatagrid.Setters.Add(new Setter { Property = MarginProperty, Value = new Thickness(2) });

var tb = new TextBlock() { FontSize = dtg.FontSize, FontFamily = dtg.FontFamily };
reportDimensionNameWidth = 0;
foreach (var item in obcMyDim)
{
tb.Text = item.NameAxisDimension;
double dim = GraphicExtensions.GetTextBlockSize(tb).Width;
if (dim > reportDimensionNameWidth)
reportDimensionNameWidth = dim + 20;
}

foreach (string label in columnLabels)
{
DataGridTextColumn column = new DataGridTextColumn();
column.Header = label;
column.HeaderStyle = styleHeaderDatagrid;
column.Binding = new Binding(label.Replace(' ', '_'));

column.Width = new DataGridLength(1, DataGridLengthUnitType.Auto);
Application.Current.Dispatcher.Invoke((Action)(() => { dtg.Columns.Add(column); }));
}

//3 adding rows
int num = 1;
for (int riga = 0; riga < numTotaleRighe; riga++)
{
dynamic newRow = new ExpandoObject();

//Adding dimension per each row
for (int colonna = 0; colonna < numTotaleColonne; colonna++)
{
string strColumnHeader = columnLabels[colonna].Replace(' ', '_');
((IDictionary<String, Object>)newRow)[strColumnHeader] = string.Empty;
switch (colonna)
{
//Here fixed lines
case 0: if (!obcMyDim[riga].IsComment) ((IDictionary<String, Object>)newRow)[strColumnHeader] = num++; break;
case 1: ((IDictionary<String, Object>)newRow)[strColumnHeader] = obcMyDim[riga].NameAxisDimension; break;
case 2: if (!obcMyDim[riga].IsComment) ((IDictionary<String, Object>)newRow)[strColumnHeader] = obcMyDim[riga].Nominal; break;
case 3: if (!obcMyDim[riga].IsComment) ((IDictionary<String, Object>)newRow)[strColumnHeader] = obcMyDim[riga].UpperTolerance; break;
case 4: if (!obcMyDim[riga].IsComment) ((IDictionary<String, Object>)newRow)[strColumnHeader] = obcMyDim[riga].LowerTolerance; break;

//Here all data
default:
if (!obcMyDim[riga].IsComment)
{
if (colonna < numTotaleColonne)
{
if ((colonna - numColonneFisse < 0) || (colonna - numColonneFisse) > obcMyDim[riga].obcItemsMeasured.Count)
{
string str = "Wrong num column obcMyDim idx=" + (colonna - numColonneFisse) + " obcmMyDim[" + riga + "].obcItemsMeasured.Count= " + obcMyDim[riga].obcItemsMeasured.Count;
MessageBox.Show(str);
}
else
((IDictionary<String, Object>)newRow)[strColumnHeader] = (obcMyDim[riga].obcItemsMeasured[colonna - numColonneFisse]).ToString();
}
else
MessageBox.Show("DtgResult Wrong column number: " + colonna);
}
break;
}
}

Serializers.Logger.WriteLog("SynchronizeDtgResults added new row num=" + riga + " name=" + obcMyDim[riga].NameAxisDimension);

Application.Current.Dispatcher.Invoke((Action)(() => { dtg.Items.Add(newRow); }));
}
Serializers.Logger.WriteLog("SynchronizeDtgResults END");
}


Again thanks for helping!!!!

Answer

This looks to be a problem related to one of the following. How the data is being populated in the data grid or how the row index is being handled. When you scroll, this causes the datagrid to refresh and update.

A couple of things to test is to turn off datavirtualization and to review DataGridCell_Load. If data virtualization being turned off does not help. There is some logic error with DataGridCell_Load.

Can you please add any additional code that can transform/modify the datagrid?

Final solution was turn of data virtualization.