I use an ObservableCollection
in my ViewModel
to add a new record in my DataGrid
, so I don't have an access to this control. I wanted to scroll to the bottom of the DataGrid
every time a new item is added.
Normally I can just hook into INotifyCollectionChanged
from my View, then scroll to the bottom, something like;
public MyView(){
InitializeComponent();
CollectionView myCollectionView = (CollectionView)CollectionViewSource.GetDefaultView(MyDataGrid.Items);
((INotifyCollectionChanged)myCollectionView).CollectionChanged = new NotifyCollectionChangedEventHandler(DataGrid_CollectionChanged);
}
private void DataGrid_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e){
if (MyDataGrid.Items.Count > 0){
if (VisualTreeHelper.GetChild(MyDataGrid, 0) is Decorator border){
if (border.Child is ScrollViewer scroll) scroll.ScrollToEnd();
}
}
}
My problem now is that I have a function to Duplicate
and Delete
an item, this whole thing is being done in my ViewModel
. With the approach above, the DataGrid will always scroll to the bottom even if I deleted or duplicate an item in any position which I don't want to happen. Scrolling to the bottom should only be working for the newly added items.
What should be the approach for this?
CodePudding user response:
You can use the passed NotifyCollectionChangedEventArgs
to identify whether a Duplicate
or Delete
has occurred.
Delete
is easy, simply:
if (e.Action == NotifyCollectionChangedAction.Remove)
{
// An item has been removed from your collection. Do not scroll.
}
Duplicate
depends on your definition of what a "duplicate" or "copy" is exactly, but most likely you can use a quick Linq check like:
if (e.Action == NotifyCollectionChangedAction.Add)
{
// An item has been added, let's see if it's a duplicate.
CollectionView changedCollection = (CollectionView)sender;
foreach (myRecordType record in e.NewItems)
{
if (changedCollection.Contains(record))
{
// This was likely a duplicate added
}
}
}
It's worth noting that EventArgs
of any type are really there for this very purpose. They'll generally provide you with more information regarding the event for exactly this kind of logical handling.
CodePudding user response:
You can try to check if NotifyCollectionChangedEventArgs.NewStartingIndex is at the end of your collection. You should scroll to the end only if the change has happened at the end.
private void DataGrid_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e){
if (MyDataGrid.Items.Count > 0 && e.NewStartingIndex == MyDataGrid.Items.Count - 1){
if (VisualTreeHelper.GetChild(MyDataGrid, 0) is Decorator border){
if (border.Child is ScrollViewer scroll) scroll.ScrollToEnd();
}
}
}