DataGrid 中未触发 NotifyOfPropertyChange

NotifyOfPropertyChange not triggered in DataGrid

我已经创建了一个 WPF 项目来说明我的项目。

免责声明:我使用 Caliburn.Micro 只是为了使用 PropertyChangedBaseBindableCollection。此项目中的其他所有内容都是样板 WPF 内容。

对,所以,我有一个classDataItem。它只有两个属性:

就是这样。为了清楚起见,这里是代码:

public class DataLine : PropertyChangedBase
{
    private int qty;

    public int Qty
    {
        get
        {
            return qty;
        }

        set
        {
            if (value == qty)
            {
                return;
            }

            qty = value;
            NotifyOfPropertyChange();
            NotifyOfPropertyChange(() => Sum);
        }
    }

    public int Sum => qty * 2;

    public DataLine(int a)
    {
        Qty = a;            
    }
}

现在,ViewModel。它有

ICommand 只为 BindableCollectionint 触发 NotifyPropertyChanged

代码如下:

class ViewModel: PropertyChangedBase
{
    public ViewModel()
    {
        Data = new BindableCollection<DataLine>
        {
            new DataLine(1),
            new DataLine(2),
            new DataLine(4),
            new DataLine(6)
        };

        RefreshCommand = new RefreshCommand(this);
    }

    private BindableCollection<DataLine> _data;

    public BindableCollection<DataLine> Data
    {
        get
        {
            return _data;
        }

        set
        {
            if (value == _data)
            {
                return;
            }

            _data = value;
            NotifyOfPropertyChange();
            NotifyOfPropertyChange(() => Amount);
        }
    }

    public ICommand RefreshCommand { get; private set; }

    public void RefreshAction()
    {
        NotifyOfPropertyChange(() => Data);
        NotifyOfPropertyChange(() => Amount);
    }

    public int? Amount => Data?.Sum(c => c.Sum);

}

现在,对于 View: 很简单。

这是 View 的正文:

<DockPanel>        
    <TextBox DockPanel.Dock="Bottom" Text="{Binding Amount, TargetNullValue='', Mode=OneWay}"/>
    <Button DockPanel.Dock="Bottom" Command="{Binding RefreshCommand}" Content="Refresh"/>
    <DataGrid ItemsSource="{Binding Data, UpdateSourceTrigger=PropertyChanged}" AutoGenerateColumns="True"/>
</DockPanel>

当我 运行 它时,我得到这样的东西:

现在是棘手的部分 - 让我只编辑其中一行。

为了清楚起见,我添加了一个箭头来显示编辑 DataGrid 后光标所在的位置。查看第一行的Sum如何更新,但屏幕底部的Amount保持不变。

现在,当我单击 Refresh 时,会发生以下情况:

Amount 现已正确更新。

所有这些最终让我想到了我的问题:DataGrid 怎么了?为什么在编辑行时 DataGrid 没有触发它的 setter?我怎样才能确保它被触发?

我发现 Datagrids 和更新 meta/aggregate 数据有时令人恼火。 目前我同意 Clemens 的观点,我不确定您是否可以轻松更改 BindableCollection 以满足您的需要。

但是,要避免在您的 DataLineViewModel 之间造成紧密结合,一个快速的解决方案是使用可以通过的 Action。你总能喜欢上一些抽象或泛型。但是我对您的代码进行了简单的编辑以表明我的意思。

本质上,您创建了一种机制,使 ViewModel 可以将 Action 传递给 Object。如果我要实现它,我可能会实现某种形式的接口或泛型,这样我就不必向每个模型添加一个操作方法。或者至少继承自具有通知操作的 class。为了清楚和方便阅读,我只是做了一个简单的编辑。

在您的数据行中添加:

//NotifyOfPropertyChange(); //NotifyOfPropertyChange(() => Sum); NotifyFromParent?.Invoke();

您的 Qty setter,并且:

   public DataLine(int a, System.Action action = null)
   {
     Qty = a;
     NotifyFromParent = action;
   }

   public System.Action NotifyFromParent;

然后在您的 ViewModel 中,您可以:

Data = new BindableCollection<DataLine>
{
   new DataLine(1, () => RefreshAction()),
   new DataLine(2, () => RefreshAction()),
   new DataLine(4, () => RefreshAction()),
   new DataLine(6, () => RefreshAction())
};

就像我说的,你可以把它做得更漂亮。据我所知,在编辑数据网格中的单元格时,您需要创建一种机制来更新聚合或外部数据,并且您希望在所述编辑之后立即进行更新。