如何强制 WPF-DataGrid 在单元格更改后直接提交对 SourceItem 的更改?

How force WPF-DataGrid to commit changes to the SourceItem directly after cell change?

我的 dataGrid 的 XAML 看起来像这样:

<DataGrid x:Name="orders"/>

通过这个函数初始化:

private void InitOrders()
{
    orders.ItemsSource = null;
    var selection = (from ord in m_DbSession.Query<Order>() select new OrderDatasource(ord, m_DbSession));
    if (selection != null)
    {
        orders.ItemsSource = selection.ToList();
    }
}

OrderDatasource 是一个 class 实现 IEditableObject 连接到数据库

class OrderDatasource : IEditableObject
{
    public OrderDatasource(Order initialObject, ISessionWrapper dbSession)
    {
        m_DbObject = initialObject;
        m_dbSession= dbSession
    }
    

    Order m_DbObject;
    ISessionWrapper m_dbSession;
    public int Count
    {
        get
        {
            return m_DbObject.Count;
        }
        set
        {
            m_DbObject.Count = value;
        }
    }

    public decimal LimitedPricePerShare
    {
        get
        {
            return m_DbObject.LimitedPricePerShare;
        }
        set
        {
            m_DbObject.LimitedPricePerShare = value;
        }
    }

    public decimal TotalPrice
    {
        get
        {
            return Count * LimitedPricePerShare;
        }
    }       
    
    public void BeginEdit()
    {

    }

    public void CancelEdit()
    {

    }

    public void EndEdit()
    {
        if (m_DBSession != null)
        {
            Debug.WriteLine("Datasource.EndEdit");
            using (var tx = m_DBSession.BeginTransaction())
            {
                m_DBSession.SaveOrUpdate(GetDbObject());
                tx.Commit();
            }
        }
        else
        {
            throw new NoDatabaseSessionProvidedException();
        }
    }       
}

所以现在我希望能够在更改单元格“Count”的内容之后但在!之前刷新 DataGrid 中 TotalPrice 的值!用户更改了所选行。

不幸的是,OrderDatasource.Count 的 setter 仅在用户单击另一行后才被调用,!不是!如果用户单击同一行中的单元格“LimitedPricePerShare”。所以“TotalPrice”的计算值是错误的。

那么:有没有办法强制 DateGrid 在单元格更改后调用 setters?

我尝试过但没有奏效的方法:

好的,看来我找到了一个方法来做到这一点。它相当复杂,但无论如何:

首先,我使用事件 AutoGeneratingColumn,我将绑定的 UpdateSourceTrigger 更改为 UpdateSourceTrigger.LostFocus

private void orders_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    if (e.Column.Header.ToString() == "Count")
    {
        var textColumn = new DataGridTextColumn();
        textColumn.Binding = new Binding(e.PropertyName) 
        { 
            UpdateSourceTrigger = UpdateSourceTrigger.LostFocus 
        };

        e.Column = textColumn;
    }
}

然后我在OrderDatasource中实现了INotifyPropertyChanged,添加了如下代码:

class OrderDatasource : IEditableObject
{
    //Same code as in the question
    //...
    
    public event PropertyChangedEventHandler PropertyChanged;
    
    protected virtual void OnPropertyChanged(string property)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(property));
    }

   public int Count
    {
        get
        {
            return m_DbObject.Count;
        }
        set
        {
            m_DbObject.Count = value;
            OnPropertyChanged(nameof(Count));
            OnPropertyChanged(nameof(TotalPrice));
        }
    }

    public decimal LimitedPricePerShare
    {
        get
        {
            return m_DbObject.LimitedPricePerShare;
        }
        set
        {
            m_DbObject.LimitedPricePerShare = value;
            OnPropertyChanged(nameof(LimitedPricePerShare));
            OnPropertyChanged(nameof(TotalPrice));
        }
    }
}

现在“TotalPrice”的值在更改列但不更改行后立即更改。

或者如果您不使用代码动态构建,则直接在 xaml 中执行。例如:

<TextBox Text="{Binding WhateverProperty, UpdateSourceTrigger=LostFocus}" />