如何强制 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?
我尝试过但没有奏效的方法:
在 CellEditEnding 事件中调用 CommitEdit
private void Orders_CellEditEnding(对象发送者,DataGridCellEditEndingEventArgs e)
{
(发件人作为 DataGrid).CommitEdit();
}
好的,看来我找到了一个方法来做到这一点。它相当复杂,但无论如何:
首先,我使用事件 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}" />
我的 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?
我尝试过但没有奏效的方法:
在 CellEditEnding 事件中调用 CommitEdit
private void Orders_CellEditEnding(对象发送者,DataGridCellEditEndingEventArgs e) { (发件人作为 DataGrid).CommitEdit(); }
好的,看来我找到了一个方法来做到这一点。它相当复杂,但无论如何:
首先,我使用事件 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}" />