当滚动时,DataGrid SelectionChanged事件是否会触发?

3
我正在尝试实现一种行为,使我的DataGrid能够移动到底部新添加的行。我有按钮可以从ItemsSource中添加/删除项目,并在添加新行时以编程方式设置SelectedCensusReportMapping
我找到了这个解决方案(https://www.codeproject.com/Tips/125583/ScrollIntoView-for-a-DataGrid-when-using-MVVM),它确实将新添加的行带入了DataGrid的视图中。但问题是,当我尝试滚动DataGrid时,当前选定的行始终保持在视图中,我无法滚动到其他行,这会将选定的行推出屏幕外。
这是我的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>

如果我通过调试逐步执行代码,我发现每当滚动DataGrid时,行为都会触发。为什么只是通过滚动DataGrid就会触发行为?无论何时滚动,都会发生这种情况,无论选定的项目是否仍然保持在屏幕上或被推出屏幕。

以下是行为代码:

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);
            }
        }
    }
}
4个回答

3
我遇到了和你在这里提到的类似问题。滚动DataGrid时,偶尔会触发几个SelectionChanged事件。
我注意到WPF DataGrid默认使用UI虚拟化,这意味着每一行DataGrid在滚动到用户的视野后都是动态生成的。
如果你将DataGrid的属性EnableRowVirtualization设置为false,则WPF将在窗口打开之前预加载所有DataGrid行。这样可以解决这个问题。
其他有用的链接: WPF Toolkit DataGrid滚动性能问题-为什么? https://learn.microsoft.com/en-us/dotnet/api/system.windows.controls.datagrid.enablerowvirtualization?view=windowsdesktop-6.0 WPF DataGrid的EnableRowVirtualization和VirtualizingStackPanel.IsVirtualizing属性的区别

PS:我仍然不确定为什么DataGrid滚动会触发selectionChanged事件,尽管自2018年以来这里的所有答案都是绕过方法,但触发行为本身仍然发生。


1
很好,这是正确的答案。没有多余的代码。这只是阻止行为发生的方法。很遗憾看到数据网格仍然有一些奇怪的特性。 - Jannick Breunis

2
我最近在使用带有ComboBoxColumn的DataGrid时遇到了同样的问题。我通过检查SelectionChangedChangedEventArgs的OriginalSource属性来解决了这个问题。
当ComboBoxColumn引起SelectionChanged事件时,OriginalSource属性是ComboBox控件。当DataGrid引起SelectionChanged事件时(例如通过设置SelectedItem),OriginalSource是DataGrid本身。
以下是适用于我的代码:
private void DataGridSelectionChanged(object sender, SelectionChangedEventArgs e)
{
    DataGrid dg = sender as DataGrid;
    if (e.OriginalSource == dg && dg.SelectedItem != null)
        dg.ScrollIntoView(dg.SelectedItem);
}

1
事件在滚动/最大化窗口等操作时触发...这看起来像是数据表格的一个bug。 根本原因:数据表格中一个或多个列的内容会触发selectionchanged事件,即使没有操作任何行。在我的情况下,它是由于一个枚举属性暴露给数据表格。我不得不将枚举属性更改为int属性,以避免在滚动时触发selectionchanged事件。 人们报告在以下情况下出现相同的行为: - 在列内使用combobox - 在列内使用listview - 等等...

0
我使用以下代码。
 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();
                        }    
                    }));
            }
        }
    }

它一直工作得很好,但最近我发现当我在我的数据网格中使用datagridcomboboxcolumn并出现某些特定的窗口时会出现问题。

奇怪的是,在某些页面上很好,但在某些窗口中却不好。

我发现当 datagridcomboboxcolumn 具有 itemsource 并且我滚动时,selectionchanged 事件会触发。

我不知道如何修复,所以我使用 datagridtemplatecolumn 并将 combobox 放入模板中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接