【发布时间】:2012-07-02 12:21:30
【问题描述】:
我希望每次 DataGrid 获得更多行或删除一些行时重新计算。我尝试使用Loaded 事件,但只触发了一次。
我找到了AddingNewItem,但它在添加之前就被触发了。我需要做我的事情之后。
还有LayoutUpdated,它可以工作,但我担心使用它是不明智的,因为对于我的目的来说它太频繁地触发了。
【问题讨论】:
我希望每次 DataGrid 获得更多行或删除一些行时重新计算。我尝试使用Loaded 事件,但只触发了一次。
我找到了AddingNewItem,但它在添加之前就被触发了。我需要做我的事情之后。
还有LayoutUpdated,它可以工作,但我担心使用它是不明智的,因为对于我的目的来说它太频繁地触发了。
【问题讨论】:
如果您的DataGrid 绑定到某些东西,我会想到两种方法。
您可以尝试获取DataGrid.ItemsSource 集合,并订阅其CollectionChanged 事件。这只有在您首先知道它是什么类型的集合时才有效。
// Be warned that the `Loaded` event runs anytime the window loads into view,
// so you will probably want to include an Unloaded event that detaches the
// collection
private void DataGrid_Loaded(object sender, RoutedEventArgs e)
{
var dg = (DataGrid)sender;
if (dg == null || dg.ItemsSource == null) return;
var sourceCollection = dg.ItemsSource as ObservableCollection<ViewModelBase>;
if (sourceCollection == null) return;
sourceCollection .CollectionChanged +=
new NotifyCollectionChangedEventHandler(DataGrid_CollectionChanged);
}
void DataGrid_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
// Execute your logic here
}
另一种解决方案是使用事件系统,例如 Microsoft Prism 的 EventAggregator 或 MVVM Light 的 Messenger。这意味着您的ViewModel 将在绑定集合更改时广播DataCollectionChanged 事件消息,而您的View 将订阅接收这些消息并在它们发生时执行您的代码。
使用EventAggregator
// Subscribe
eventAggregator.GetEvent<CollectionChangedMessage>().Subscribe(DoWork);
// Broadcast
eventAggregator.GetEvent<CollectionChangedMessage>().Publish();
使用Messenger
//Subscribe
Messenger.Default.Register<CollectionChangedMessage>(DoWork);
// Broadcast
Messenger.Default.Send<CollectionChangedMessage>()
【讨论】:
ViewModelBase 是我通常在所有 ViewModel 上实现的自定义类。在您的情况下,只需将其转换为您的 ItemsSource 中的任何类型的项目。
DataGrid.LoadingRow(object sender, DataGridRowEventArgs e)怎么样?
卸载也是如此。
DataGrid.UnLoadingRow(object sender, DataGridRowEventArgs e)?
【讨论】:
DataGrid 的数据源添加新行。此事件与可视行(DataGridRow 对象)相关,与数据源中的行无关。
ObservableCollection。
您是否尝试过 MVVM 方法并绑定到 Observable 集合?
public ObservableCollection<Thing> Items{
get { return _items; }
set{ _items = value; RaisePropertyChanged("Items"); // Do additional processing here
}
}
所以您可以在不受 UI 约束的情况下观看项目的添加/删除?
【讨论】:
如果您愿意,您可以按照其他人在此处描述的那样走 RowUnloading 路线,但请注意,每次一行失去焦点时也会触发此事件。
但是,通过玩耍,我发现当删除一行时,网格的SelectedItem 属性为空,而CurrentItem 属性不为空,到目前为止,我只看到此组合用于已删除的行,(虽然我不能保证我没有错过一个异国情调的情况......但是对于远离行的基本情况我到目前为止还没有看到)。
那么什么时候可以使用下面的代码只过滤已删除的行:
private void CategoriesGrid_UnloadingRow(object sender, DataGridRowEventArgs e)
{
if (((DataGrid)sender).SelectedItem != null || ((DataGrid)sender).CurrentItem == null)
{
return;
}
// The rest of your code goes here
}
【讨论】:
如果你想使用 ObservableCollection 并获得关于添加或其他操作的通知,最好的方法是使用 INotifyCollectionChanged
var source = datagrid.ItemsSource as INotifyCollectionChanged;
因为,当你解包到ObservableCollection<MyClass>()时,你必须写srogly MyClass(不是ObservableCollection<ParentOfMyClass>())
【讨论】:
根据您要重新计算的“事物”,您可以考虑使用 ScrollViewer.ScrollChanged 附加事件。这可以在 XAML 中设置如下:
<DataGrid
...
ScrollViewer.ScrollChanged="control_ScrollChanged">
ScrollChangedEventArgs 对象具有各种有助于计算布局和滚动位置(Extent、Offset、Viewport)的属性。请注意,在使用默认虚拟化设置时,这些通常以行数/列数来衡量。
【讨论】:
我一直在寻找解决方案,我找到了处理这个问题的完美事件,该事件称为 UnloadingRow
<DataGrid ....
UnloadingRow="DataGrid_UnloadingRow">
...
</DataGrid>
在你的 C# 代码中你会得到这个
private void ProductsDataGrid_UnloadingRow(object sender, DataGridRowEventArgs e)
{
MyObject obj = (MyObject)e.Row.Item; // get the deleted item to handle it
// Rest of your code ...
// For example : deleting the object from DB using entityframework
}
【讨论】: