'DataGrid SelectionChanged event firing when scrolling

I am trying to implement a behavior to allow my DataGrid to move to a newly added row at the bottom of the DataGrid. I have buttons that add/remove items from the ItemsSource and programatically set the SelectedCensusReportMapping when adding a new row.

I found this solution (https://www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-when-using-MVVM) which does bring the newly added row into view within the DataGrid. The issue I am having is that when I try to scroll the DataGrid, the currently selected row always remains in view and I cannot scroll to other rows which would push the selected row off screen.

Here is the implementation of my DataGrid:

     <DataGrid Name="DataGrid_CensusReportMapping"
                     ItemsSource="{Binding Model.CensusReportMappings, UpdateSourceTrigger=PropertyChanged}"
                     SelectedItem="{Binding SelectedCensusReportMapping, UpdateSourceTrigger=PropertyChanged}"    
                     AutoGenerateColumns="False"
                     CanUserAddRows="False"
                     CanUserDeleteRows="False">

        <i:Interaction.Behaviors>
            <h:ScrollIntoDataGridBehavior />
        </i:Interaction.Behaviors>
</DataGrid>

If I step through the code via debug, I find that whenever the DataGrid is scrolled, the behavior is firing. Why is the behavior firing simply by scrolling the DatGrid. This happens anytime I scroll, regardless if by scrolling the selected item would remain on screen or get pushed off-screen.

Here is the behavior code:

public class ScrollIntoDataGridBehavior : Behavior<DataGrid>
{
    /// <summary>
    /// Override of OnAttached() method to add SelectionChanged event handler
    /// </summary>
    protected override void OnAttached()
    {
        base.OnAttached();
        this.AssociatedObject.SelectionChanged += new SelectionChangedEventHandler(AssociatedObject_SelectionChanged);
    }

    /// <summary>
    /// Override of OnDetaching() method to add SelectionChanged event handler
    /// </summary>
    protected override void OnDetaching()
    {
        base.OnDetaching();
        this.AssociatedObject.SelectionChanged -=
            new SelectionChangedEventHandler(AssociatedObject_SelectionChanged);
    }

    /// <summary>
    /// When the selection is changed, re-focus on new selection using the ScrollIntoView method
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (sender is DataGrid)
        {
            DataGrid grid = (sender as DataGrid);
            if (grid.SelectedItem != null)
            {
                Action action = delegate()
                {
                    grid.UpdateLayout();
                    if (grid.SelectedItem != null)
                    {
                        grid.ScrollIntoView(grid.SelectedItem, null);
                    }
                };

                grid.Dispatcher.BeginInvoke(action);
            }
        }
    }
}


Solution 1:[1]

I recently faced the same issue on a DataGrid with a ComboBoxColumn. I managed to get arround this issue by checking the OriginalSource property of the SelectionChangedChangedEventArgs.

When the SelectionChanged event is caused by the ComboBoxColumn, the OriginalSource property is the ComboBox control. When the SelectionChanged event is caused by the Datagrid (e.g. by setting the SelectedItem) the OriginalSource is the DataGrid itself.

Here is the code that worked for me

private void DataGridSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    DataGrid dg = sender as DataGrid;
    if (e.OriginalSource == dg && dg.SelectedItem != null)
        dg.ScrollIntoView(dg.SelectedItem);
}

Solution 2:[2]

I am facing the similar issue that you had here. Several SelectionChanged events got triggered occationally when scrolling the DataGrid.

What I noticed was that WPF DataGrid is using UI Virtualization by default, which means that each row of DataGrid is dynamically generalized after scrolling to user's sight.

If you turn EnableRowVirtualization, the property of DataGrid, to false. WPF would then preload all rows of DataGrid before window opened. And that would managed to get around this problem.

other helpful links: WPF Toolkit DataGrid scrolling performance problems - why? https://docs.microsoft.com/en-us/dotnet/api/system.windows.controls.datagrid.enablerowvirtualization?view=windowsdesktop-6.0 Difference between WPF DataGrid's EnableRowVirtualization and VirtualizingStackPanel.IsVirtualizing properties

PS: I am still not so sure why the DataGrid Scrolling would trigger selectionChanged, though. All answers here since 2018 are all bypasses but the triggering behavior itself still occurred.

Solution 3:[3]

Event firing on scroll/maximize window... etc. This looks like a datagrid bug. Root cause : the content of one or more columns in the datagrid is responsible for triggering the selectionchanged event even if no row has been touched. In my case it was due to an Enum property exposed to the datagrid. I had to change the Enum property to an int property to avoid the selectionchanged even firing on scroll.

People have reported the same behavior when using : - combobox inside a column - listview inside a column - etc....

Solution 4:[4]

I use below code.

 void AssociatedObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        if (sender is DataGrid)
        {          
            DataGrid grid = (sender as DataGrid);                
            if (grid.SelectedItem != null)
            {                
                grid.Dispatcher.BeginInvoke(
                    (Action)(() =>
                    {                            
                        if (grid.SelectedItem != null)
                        {
                            grid.ScrollIntoView(grid.SelectedItem);
                            grid.UpdateLayout();
                        }    
                    }));
            }
        }
    }

It work fine,but recently i found when i use datagridcomboboxcolumn in my datagrid and some specific window occured your problem.

Strangely,in some page is fined ,but in some window is no fined

i found is selectionchanged event trigger when datagridcomboboxcolumn has itemsource and i scrolling.

i don't know how to fix,so i use datagridtemplatecolumn and put combobox in template

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Tobias Hoefer
Solution 2 Haiming
Solution 3 Vladimir Putin
Solution 4 tszzz