You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WinUI3 DataGrid修改单元格A后单元格B不更新问题求助

问题:WinUI3 DataGrid中TotalPreis单元格不自动更新值

我在WinUI3项目中使用CommunityToolkit.WinUI.UI.Controls.DataGrid,将ObservableCollection<ExampleClass>绑定到DataGrid。ExampleClass包含字段Amount int, Price int, TotalPrice int(对应德语Anzahl、Preis、TotalPreis)。我给DataGrid添加了CellEditEnded事件,用于将TotalPrice更新为Amount * Price。

运行时用户修改Anzahl或Preis后,ObservableCollection中的TotalPreis值已正确更新,但DataGrid的TotalPreis单元格仍显示旧值(例如初始Preis为10,修改Anzahl为2后仍显示0)。只有刷新页面或开始编辑TotalPreis单元格时,才会显示正确值;手动修改TotalPreis时也会自动恢复为计算后的正确值。

尝试过修改绑定模式、UpdateSourceTrigger等XAML属性,均无效,寻求解决方案(临时方案也可接受)。

相关XAML代码

<controls:DataGrid 
    AutoGenerateColumns="False"
    GridLinesVisibility="Horizontal"
    ItemsSource="{x:Bind ViewModel.kgr.Tabelle1, Mode=OneWay}"
    Grid.Column="0"
    Grid.Row="0"
    CellEditEnded="DataGrid_CellEditEnded">
    <controls:DataGrid.Resources>
        <SolidColorBrush x:Key="DataGridColumnHeaderBackgroundColor" Color="Transparent" />
    </controls:DataGrid.Resources>
    <controls:DataGrid.Columns>
        <controls:DataGridTextColumn Binding="{Binding Name}" Header="Bereich" />
        <controls:DataGridTextColumn Binding="{Binding Anzahl}" Header="Fläche in m^2" />
        <controls:DataGridTextColumn Binding="{Binding Preis}" Header="€ pro m^2" />
        <controls:DataGridTextColumn Binding="{Binding TotalPreis}" Header="Gesamt"/>
        <!-- IsReadOnly="True" -->
    </controls:DataGrid.Columns>
</controls:DataGrid>

解决方案

1. 根本解决:让实体类实现INotifyPropertyChanged

ObservableCollection仅监听集合的增删改操作,不会自动感知集合内对象的属性变化。让ExampleClass实现INotifyPropertyChanged接口,在属性更新时触发通知,UI会自动刷新对应的单元格。

public class ExampleClass : INotifyPropertyChanged
{
    private int _anzahl;
    public int Anzahl
    {
        get => _anzahl;
        set
        {
            if (_anzahl != value)
            {
                _anzahl = value;
                OnPropertyChanged(nameof(Anzahl));
                UpdateTotalPreis();
            }
        }
    }

    private int _preis;
    public int Preis
    {
        get => _preis;
        set
        {
            if (_preis != value)
            {
                _preis = value;
                OnPropertyChanged(nameof(Preis));
                UpdateTotalPreis();
            }
        }
    }

    private int _totalPreis;
    public int TotalPreis
    {
        get => _totalPreis;
        set
        {
            if (_totalPreis != value)
            {
                _totalPreis = value;
                OnPropertyChanged(nameof(TotalPreis));
            }
        }
    }

    private void UpdateTotalPreis()
    {
        TotalPreis = Anzahl * Preis;
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

使用这种方式后,无需依赖CellEditEnded事件,修改Anzahl或Preis时会自动计算并更新TotalPreis,UI同步刷新,符合MVVM设计模式。

2. 临时方案:手动刷新TotalPreis单元格

如果暂时不想修改实体类,可以在CellEditEnded事件中手动找到对应单元格并强制刷新绑定:

private void DataGrid_CellEditEnded(object sender, DataGridCellEditEndedEventArgs e)
{
    var dataGrid = sender as DataGrid;
    if (dataGrid == null || e.Row.DataContext == null) return;

    var item = e.Row.DataContext as ExampleClass;
    if (item == null) return;

    // 计算更新TotalPreis
    item.TotalPreis = item.Anzahl * item.Preis;

    // 定位TotalPreis列
    var totalColumn = dataGrid.Columns.FirstOrDefault(c => c.Header.ToString() == "Gesamt");
    if (totalColumn == null) return;

    // 获取对应单元格并刷新绑定
    var cell = dataGrid.GetCell(e.Row, totalColumn);
    cell?.BindingExpression?.UpdateTarget();
}

// 扩展方法:获取指定行和列的DataGridCell
public static DataGridCell GetCell(this DataGrid dataGrid, DataGridRow row, DataGridColumn column)
{
    if (row == null || column == null) return null;
    
    var presenter = row.FindVisualChild<DataGridCellsPresenter>();
    if (presenter == null)
    {
        row.ApplyTemplate();
        presenter = row.FindVisualChild<DataGridCellsPresenter>();
    }

    return presenter != null ? column.GetCellContent(presenter)?.Parent as DataGridCell : null;
}

// 辅助扩展方法:查找视觉树中的子元素
public static T FindVisualChild<T>(this DependencyObject parent) where T : DependencyObject
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
    {
        var child = VisualTreeHelper.GetChild(parent, i);
        if (child is T tChild) return tChild;
        
        var result = FindVisualChild<T>(child);
        if (result != null) return result;
    }
    return null;
}

额外优化

建议将TotalPreis列设置为只读,避免用户手动修改后自动恢复的突兀体验:

<controls:DataGridTextColumn Binding="{Binding TotalPreis}" Header="Gesamt" IsReadOnly="True"/>

内容的提问来源于stack exchange,提问作者EddyChicken

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 07:24:58