WPF多线程更新绑定值时Converter未触发问题求助
问题:后台线程更新DataTable时DataGrid单元格Converter未触发
WPF应用中,DataGrid绑定C#的DataTable,通过CellColorConverter根据单元格值改变背景色。正常使用功能正常,但通过单独线程更新DataTable的值时,单元格显示值更新,却无法触发Converter。尝试触发NotifyPropertyChanged事件无效,寻求解决方法。
DataGrid XAML代码
<UserControl.Resources> <utility:CellColorConverter x:Key="ColorConverter" /> <Style x:Key="BlueDataGridStyle" TargetType="{x:Type DataGrid}"> <Setter Property="CellStyle" Value="{DynamicResource BlueDataGridCellStyle}" /> </Style> <Style x:Key="BlueDataGridCellStyle" TargetType="DataGridCell" > <Setter Property="Background"> <Setter.Value> <MultiBinding Converter="{StaticResource ColorConverter}"> <MultiBinding.Bindings> <Binding RelativeSource="{RelativeSource Self}" /> <Binding Path="Row" /> </MultiBinding.Bindings> </MultiBinding> </Setter.Value> </Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type DataGridCell}"> <Grid Background="{TemplateBinding Background}"> <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" /> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </UserControl.Resources> <DataGrid Name="dgSimple" AutoGenerateColumns="True" ItemsSource="{Binding Grid}" IsReadOnly="True" CanUserResizeColumns="False" CanUserResizeRows="False" CanUserSortColumns="False" CanUserReorderColumns="False" Margin="6" SelectedIndex="{Binding SelectedRow}" CurrentColumn="{Binding SelectedColumn}" Style="{StaticResource BlueDataGridStyle}" HeadersVisibility="All" RowHeaderWidth="32" ColumnWidth="32"> </DataGrid>
Converter C#代码
public class CellColorConverter : IMultiValueConverter { object IMultiValueConverter.Convert(object[] values, Type targetType, object parameter, CultureInfo culture) { if (values[0] is DataGridCell cell && values[1] is DataRow row) { try { string columnName = (string)cell.Column.Header; int columnIndex = cell.Column.DisplayIndex; if (columnIndex == 0) { cell.FontStyle = FontStyles.Italic; cell.FontWeight = FontWeights.Bold; cell.FontSize = 20; return new SolidColorBrush(Colors.Yellow); } string content = row.Field<string>(columnName); // Header must be same as column name if (content == "w") { return new SolidColorBrush(Colors.Blue); } if (content == "h") { return new SolidColorBrush(Colors.Red); } if (content == "m") { return new SolidColorBrush(Colors.LightGray); } if (content == "c" || content == "b" || content == "s" || content == "d" || content == "p") { return new SolidColorBrush(Colors.Gray); } } catch (Exception e) { Debug.WriteLine(e); return new SolidColorBrush(Colors.Black); // Error! An Exception was thrown } } return new SolidColorBrush(Colors.Green); // Something else. } object[] IMultiValueConverter.ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) { throw new NotSupportedException(); } }
解决方法
1. 用Dispatcher切换到UI线程更新DataTable
后台线程直接修改DataTable时,WPF可能无法正确捕获变更通知,需通过UI线程执行更新:
Application.Current.Dispatcher.Invoke(() => { // 执行DataTable单元格更新操作 yourDataTable.Rows[rowIndex][columnName] = "newValue"; });
但这种方式仅保证值更新,仍可能无法触发Converter,需结合绑定刷新。
2. 强制刷新目标单元格的绑定
更新DataTable后,找到对应DataGridCell并强制刷新Background属性的绑定:
var rowContainer = dgSimple.ItemContainerGenerator.ContainerFromIndex(rowIndex) as DataGridRow; if (rowContainer != null) { var column = dgSimple.Columns[columnIndex]; var cell = column.GetCellContent(rowContainer)?.Parent as DataGridCell; if (cell != null) { Application.Current.Dispatcher.Invoke(() => { cell.GetBindingExpression(DataGridCell.BackgroundProperty)?.UpdateTarget(); }); } }
3. 修改MultiBinding绑定源为单元格具体值
当前MultiBinding绑定了整个Row,无法感知单个单元格值变更。可改为直接绑定单元格值(自动生成列场景需额外处理列名):
<MultiBinding Converter="{StaticResource ColorConverter}"> <Binding RelativeSource="{RelativeSource Self}" /> <Binding Path="Row[YourColumnName]" /> </MultiBinding>
4. 改用ObservableCollection替代DataTable
DataTable的变更通知机制不够灵活,改用实现INotifyPropertyChanged的实体类集合:
public class GridItem : INotifyPropertyChanged { private string _column1; public string Column1 { get => _column1; set { _column1 = value; OnPropertyChanged(); } } // 其他列属性... public event PropertyChangedEventHandler PropertyChanged; private void OnPropertyChanged([CallerMemberName] string propName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } }
初始化时开启集合同步,允许后台线程安全更新:
// ViewModel初始化时执行 BindingOperations.EnableCollectionSynchronization(YourObservableCollection, new object()); // 后台线程中直接更新属性 YourObservableCollection[rowIndex].Column1 = "newValue";
5. 重新绑定DataGrid的ItemsSource
简单粗暴的方式,强制DataGrid重新渲染所有单元格:
Application.Current.Dispatcher.Invoke(() => { var temp = dgSimple.ItemsSource; dgSimple.ItemsSource = null; dgSimple.ItemsSource = temp; });
适合数据量较小的场景。
内容的提问来源于stack exchange,提问作者Nox
相关产品推荐
相关产品推荐

