How to reload/refresh particular row in WPF DataGrid

Nov 10, 2008 at 6:46 AM
I use LoadingRow event to change row background color dependently of row data. It works, but if I change some data in row's item by code (I use INotifyPropertyChanged), the data in grid changes, not color. So I need to force row reloading.

My question it: how to reload/refresh particular row? Without Items.Refresh?
Coordinator
Nov 10, 2008 at 12:30 PM
You can do a DataGridRow.UpdateLayout().
Nov 10, 2008 at 1:16 PM
Unfortunately, UpdateLayout does not took into account Background binding, so it's does not work.
Coordinator
Nov 10, 2008 at 5:18 PM
Could you show a code snippet.
Nov 11, 2008 at 5:46 AM

Ok, for example, I have my SimpleEntity as a Item:

  public class SimpleEntity : INotifyPropertyChanged
{
public int Id {get; set; }
public string Name { get; set; }
public string Key1 { get; set; }

public SimpleEntity(int id, string name)
{
Id = id;
Name = name;
Key1 = "";
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
public void NotifyAll()
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs("Key1"));
//PropertyChanged(this, new PropertyChangedEventArgs("LU1"));
}
}

}

public class SimpleEntityList : ObservableCollection<SimpleEntity>
{
}

And my descendant for DataGrid which can expose row by index:

  public class MyDataGrid : DataGrid
{
public DataGridRow RowByIndex(int index)
{
DataGridRow R = (DataGridRow)ItemContainerGenerator.ContainerFromIndex(index);
return R;
}

}

Ok, I create all in code, not XAML:

  private void button1_Click(object sender, RoutedEventArgs e)
{
for (int i = 0; i < 200; i++)  tbl.Add(new SimpleEntity(i, "Text_" + i));

myDataGrid1.AutoGenerateColumns = false;

DataGridTextColumn col1 = new DataGridTextColumn();
col1.Header = "Code";
col1.Binding = new Binding("Id");
myDataGrid1.Columns.Add(col1);

DataGridTextColumn col2 = new DataGridTextColumn();
col2.Header = "Description";
col2.Binding = new Binding("Name");
myDataGrid1.Columns.Add(col2);

DataGridTemplateColumn col3 = new DataGridTemplateColumn();
DataTemplate col3Template = new DataTemplate();
Binding binding3 = new Binding("Key1");
FrameworkElementFactory cellTemplateFactory3 = new FrameworkElementFactory(typeof(TextBlock));
cellTemplateFactory3.SetBinding(TextBlock.TextProperty, binding3);
col3Template.VisualTree = cellTemplateFactory3;
col3.CellTemplate = col3Template;
col3.Header = "Key1";

Binding binding3bk = new Binding();
binding3bk.Converter = new MyBrushConverter();
binding3bk.ConverterParameter = "SomeParam";
cellTemplateFactory3.SetBinding(TextBlock.BackgroundProperty, binding3bk);


myDataGrid1.Columns.Add(col3);

myDataGrid1.ItemsSource = tbl;
}

Also, converter for Background binding to highlight cell:

  public class MyBrushConverter : IValueConverter
{
protected static SolidColorBrush RedBrush;
protected static SolidColorBrush GreenBrush;

static MyBrushConverter()
{
RedBrush = new SolidColorBrush(Colors.Green);
GreenBrush = new SolidColorBrush(Colors.Yellow);
RedBrush.Freeze();
GreenBrush.Freeze();

}
#region IValueConverter Members

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
SimpleEntity sac = value as SimpleEntity;
if (sac != null && targetType == typeof(Brush) && parameter is string)
{
bool bCheck = false;
if ((string)parameter == "SomeParam")
{
bCheck = sac.Key1.Length > 5;
}

if (bCheck)
return GreenBrush;
else
return RedBrush;
}
return null;
}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}

#endregion

}

Ok, that's all. Now we can try to change some values:

  private void button3_Click(object sender, RoutedEventArgs e)
{
tbl[2].Key1 = "7777777";
tbl[2].NotifyAll();
myDataGrid1.RowByIndex(2).UpdateLayout();
}

And we can see, that value in cell was changed; but cell background remains green, not red.



Nov 11, 2008 at 5:51 AM

But, if I add

  private void button3_Click(object sender, RoutedEventArgs e)
{
tbl[2].Key1 = "7777777";
tbl[2].NotifyAll();
myDataGrid1.Items.Refresh();
}

Background of cell changes after .Items.Refresh(); So, .Items.Refresh() works and RowByIndex(2).UpdateLayout() does not work.

Aug 11, 2010 at 11:48 AM
I have similar problem. Is there any solution?
Aug 22, 2010 at 5:35 AM

I attempted to use the Items.Refresh() method, but it was to slow. 

Instead, something that performs much better is to remove the line-item from the source list and re-insert it at the same index. It updates the row because it is a "newly added row".