DataGrid 中未触发 NotifyOfPropertyChange
NotifyOfPropertyChange not triggered in DataGrid
我已经创建了一个 WPF 项目来说明我的项目。
免责声明:我使用 Caliburn.Micro 只是为了使用 PropertyChangedBase
和 BindableCollection
。此项目中的其他所有内容都是样板 WPF 内容。
对,所以,我有一个classDataItem
。它只有两个属性:
- 一个
int
叫 Qty
,
- 一个计算的 属性 称为
Sum
,它
是 Qty
. 的两倍
就是这样。为了清楚起见,这里是代码:
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。它有
- a
BindableCollection
(这是 Caliburn 的 ObservableCollection
风味) of DataLine
,
- 一个
int
,它将把DataLines
的所有Sum
和 相加
- 一个 ICommand。
ICommand 只为 BindableCollection
和 int
触发 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
:
很简单。
- 有一个
DataGrid
,绑定到 BindableCollection
。
- 有一个
Button
,绑定到 ICommand
。
- 有一个“文本框
, bound to
金额”。
这是 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 以满足您的需要。
但是,要避免在您的 DataLine
和 ViewModel
之间造成紧密结合,一个快速的解决方案是使用可以通过的 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())
};
就像我说的,你可以把它做得更漂亮。据我所知,在编辑数据网格中的单元格时,您需要创建一种机制来更新聚合或外部数据,并且您希望在所述编辑之后立即进行更新。
我已经创建了一个 WPF 项目来说明我的项目。
免责声明:我使用 Caliburn.Micro 只是为了使用 PropertyChangedBase
和 BindableCollection
。此项目中的其他所有内容都是样板 WPF 内容。
对,所以,我有一个classDataItem
。它只有两个属性:
- 一个
int
叫Qty
, - 一个计算的 属性 称为
Sum
,它 是Qty
. 的两倍
就是这样。为了清楚起见,这里是代码:
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。它有
- a
BindableCollection
(这是 Caliburn 的ObservableCollection
风味) ofDataLine
, - 一个
int
,它将把DataLines
的所有Sum
和 相加
- 一个 ICommand。
ICommand 只为 BindableCollection
和 int
触发 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
:
很简单。
- 有一个
DataGrid
,绑定到BindableCollection
。 - 有一个
Button
,绑定到ICommand
。 - 有一个“文本框
, bound to
金额”。
这是 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 以满足您的需要。
但是,要避免在您的 DataLine
和 ViewModel
之间造成紧密结合,一个快速的解决方案是使用可以通过的 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())
};
就像我说的,你可以把它做得更漂亮。据我所知,在编辑数据网格中的单元格时,您需要创建一种机制来更新聚合或外部数据,并且您希望在所述编辑之后立即进行更新。