如何正确通知数据网格其数据集已过时?
How to properly notify the datagrid that its data set is outdated?
我的 DataGrid 控件绑定到视图模型及其 getter 中的 ListCollectionView 实例,我检查对于基础 属性 AllThings。到目前为止,支持字段 _allThings 的填充已在视图模型的构造函数中执行,并且由于数据库中的数据仅在一夜之间发生变化,因此已经足够了。
但是,截至目前,将创建新的 Thing 实例并将其射入数据库。假设用户单击了一个按钮,该按钮触发了方法 UpdateData(Object, RoutedEventArgs) 中处理的事件,重新呈现数据网格的合适方法是什么?
属性 AllThings 是否必须为 ObservableCollection 类型,或者与 IEnumerable? (将来,如果数据库 中的相关更改 目前没有任何问题,我可能想更新网格。)
我对正确方法如此好奇的原因是数据来源不同。通常,数据来自 导致新数据可用事件的同一控件 上的绑定。在这里,控件(按钮)将通知有一些新数据,但它来自 来自另一个来源,即数据库。我不确定是否应该以不同的方式处理它,如果是,如何处理。
在public接口上暴露IEnumerable
就足够了。您不想公开超出需要的内容,公开 ObservableCollection
将允许外部 类 修改集合。
public class Model
{
private readonly ObservableCollection<Thing> _allThings = new ObservableCollection<Thing>();
public IEnumerable<Thing> AllThings { get { return _allThings; }}
}
请注意,我不允许更改它的引用,(它是 readonly
)如果它的引用被更改(通过通知),它将导致网格的完全刷新。用户将松开他们的位置,任何选择和网格将跳到顶部。
绑定到 AllThings
即可,无需更多工作来通知更改视图。
旁白:ObservableCollection
相对于 List
的一个显着缺点是,你不能 AddRange
,但请参阅此问题以解决该问题:ObservableCollection Doesn't support AddRange method, so I get notified for each item added, besides what about INotifyCollectionChanging?
WPF 中的更改通知基于 INotifyPropertyChanged。
对于消费者(您的 DataGrid)来说,它只是一个事件(PropertyChanged),当某些更改发生时触发。绑定引擎将相应地刷新 DataGrid。
您必须在 ViewModel 中实现 INotifyPropertyChanged,并根据需要触发事件(即在用户按下 "reload data" 按钮后)
public class Car
{
public string Model;
public int Speed;
}
class MyViewModel: INotifyPropertyChanged
{
List<Car> cars;
public List<Car> Cars { get {return cars;}}
// this method is invoked from GUI, ie from an event handler or a Command of a "Reload" button
public void ReloadData()
{
// do something to actually refresh cars
// notify GUI something changed
InternalPropertyChanged("Cars");
}
public event PropertyChangedEventHandler PropertyChanged;
protected void InternalPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
这样整个列表就会刷新,正如 Weston 指出的那样,会重置网格选择和位置。
ObservableCollection 更进一步,检测单个元素的插入或删除并只允许刷新它们。但它不会检测现有元素的变化(即如果现有汽车的速度发生变化)。
要检测和刷新现有元素更改,您必须对单个元素(即 class 汽车)实施 INotifyPropertyChanged。
另请注意,如果您的数据库查询从头开始创建新列表(所有数据库 API 通常都会这样做),ObservableCollection 不会添加任何内容。
您应该从数据库中获取新列表,将其与现有列表进行比较,然后在 ObservableCollection 上调用 Add/Remove(这可能不值得)
我的 DataGrid 控件绑定到视图模型及其 getter 中的 ListCollectionView 实例,我检查对于基础 属性 AllThings。到目前为止,支持字段 _allThings 的填充已在视图模型的构造函数中执行,并且由于数据库中的数据仅在一夜之间发生变化,因此已经足够了。
但是,截至目前,将创建新的 Thing 实例并将其射入数据库。假设用户单击了一个按钮,该按钮触发了方法 UpdateData(Object, RoutedEventArgs) 中处理的事件,重新呈现数据网格的合适方法是什么?
属性 AllThings 是否必须为 ObservableCollection 类型,或者与 IEnumerable? (将来,如果数据库 中的相关更改 目前没有任何问题,我可能想更新网格。)
我对正确方法如此好奇的原因是数据来源不同。通常,数据来自 导致新数据可用事件的同一控件 上的绑定。在这里,控件(按钮)将通知有一些新数据,但它来自 来自另一个来源,即数据库。我不确定是否应该以不同的方式处理它,如果是,如何处理。
在public接口上暴露IEnumerable
就足够了。您不想公开超出需要的内容,公开 ObservableCollection
将允许外部 类 修改集合。
public class Model
{
private readonly ObservableCollection<Thing> _allThings = new ObservableCollection<Thing>();
public IEnumerable<Thing> AllThings { get { return _allThings; }}
}
请注意,我不允许更改它的引用,(它是 readonly
)如果它的引用被更改(通过通知),它将导致网格的完全刷新。用户将松开他们的位置,任何选择和网格将跳到顶部。
绑定到 AllThings
即可,无需更多工作来通知更改视图。
旁白:ObservableCollection
相对于 List
的一个显着缺点是,你不能 AddRange
,但请参阅此问题以解决该问题:ObservableCollection Doesn't support AddRange method, so I get notified for each item added, besides what about INotifyCollectionChanging?
WPF 中的更改通知基于 INotifyPropertyChanged。
对于消费者(您的 DataGrid)来说,它只是一个事件(PropertyChanged),当某些更改发生时触发。绑定引擎将相应地刷新 DataGrid。
您必须在 ViewModel 中实现 INotifyPropertyChanged,并根据需要触发事件(即在用户按下 "reload data" 按钮后)
public class Car
{
public string Model;
public int Speed;
}
class MyViewModel: INotifyPropertyChanged
{
List<Car> cars;
public List<Car> Cars { get {return cars;}}
// this method is invoked from GUI, ie from an event handler or a Command of a "Reload" button
public void ReloadData()
{
// do something to actually refresh cars
// notify GUI something changed
InternalPropertyChanged("Cars");
}
public event PropertyChangedEventHandler PropertyChanged;
protected void InternalPropertyChanged(string name)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
这样整个列表就会刷新,正如 Weston 指出的那样,会重置网格选择和位置。
ObservableCollection 更进一步,检测单个元素的插入或删除并只允许刷新它们。但它不会检测现有元素的变化(即如果现有汽车的速度发生变化)。
要检测和刷新现有元素更改,您必须对单个元素(即 class 汽车)实施 INotifyPropertyChanged。
另请注意,如果您的数据库查询从头开始创建新列表(所有数据库 API 通常都会这样做),ObservableCollection 不会添加任何内容。
您应该从数据库中获取新列表,将其与现有列表进行比较,然后在 ObservableCollection 上调用 Add/Remove(这可能不值得)