Home > Net >  DataGrid auto scroll to bottom for newly added item
DataGrid auto scroll to bottom for newly added item

Time:08-13

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();
        }
    }
}
  • Related