【问题标题】:WPF DataGrid scrolling with down arrow key acts strangely使用向下箭头键滚动的 WPF DataGrid 行为奇怪
【发布时间】:2012-06-19 15:57:46
【问题描述】:

我有一个 WPF DataGrid,我已经使用了一段时间,而且效果很好。与这里的其他海报不同,我还没有遇到滚动条或鼠标滚轮的问题。我已将 CTRLEND 编程为转到 DataGrid 的末尾,然后它会跟踪最近添加的项目。我可以使用 up 键向上滚动 DataGrid 的内容。

但是,我使用 down 键的行为非常奇怪!如果我从DataGrid 的顶部开始并按住 down 键,它会滚动一点,然后最终在相邻的两行之间来回反弹。如果我 pgdn,它将向下滚动更多,然后跳回到它会在其间跳转的前两行的最顶部,然后向下滚动到我 pgdn 的位置会的。如果我再向下翻页,down 键将滚动到最后。如果我转到 DataGrid 的顶部并重新开始,我会一遍又一遍地得到完全相同的行为。

我还没有找到解决这个问题的帖子,而且我在DataGrid 文档中也没有看到任何有帮助的内容。

这只是一个三列DataGrid,其中每列显示TextBlocks。谁能解释为什么只有这一种滚动模式有问题?这是 XAML:

<DataGrid ItemsSource="{Binding MainLog}" AutoGenerateColumns="False" 
     Name="log_datagrid" SelectedCellsChanged="log_datagrid_SelectedCellsChanged"   
     KeyUp="datagrid_KeyUp" LoadingRow="log_datagrid_LoadingRow">
    <DataGrid.Columns>
        <!-- timestamp -->
        <DataGridTemplateColumn Header="Timestamp">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Timestamp}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <!-- level -->
        <DataGridTemplateColumn Header="Level">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Level}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
        <!-- error message -->
        <DataGridTemplateColumn Header="Message">
            <DataGridTemplateColumn.CellTemplate>
                <DataTemplate>
                    <TextBlock Text="{Binding Message}" />
                </DataTemplate>
            </DataGridTemplateColumn.CellTemplate>
        </DataGridTemplateColumn>
    </DataGrid.Columns>
</DataGrid>

顺便说一句,即使我的所有事件处理程序的代码隐藏都被注释掉了,这种行为也会发生。

这是我的 MainLog 集合包含的结构的定义:

public struct MainLogData
{
    public string Timestamp { get; set; }
    public string Level { get; set; }
    public string Message { get; set; }
}

【问题讨论】:

  • 我在使用 wpf 和网格时也会出现奇怪的行为,甚至到了 Visual Studio 崩溃导致内存不足的地步,可能添加更多 RAM 会帮助您解决问题
  • 添加更多 RAM 绝不是解决内存不足异常的方法。 ;) 也许您的数据网格单元格正在使用需要为 Disposed 的对象。
  • 您的 MainLog 集合中的类是否具有 Equals 方法的自定义实现?
  • @alittlesheep 不,它没有。

标签: c# wpf .net-4.0 datagrid wpfdatagrid


【解决方案1】:

好的...我用字符串重现了该行为(绑定到数据网格的字符串的简单列表)。当我在列表中引入重复字符串时,这种行为开始发生。似乎数据网格在“选定索引”和“选定值”之间混淆了。 当我尝试选择另一个可见行上存在的值(在我的测试中是一个字符串)时,也会发生同样的事情:选择被搞砸了:有一半的时间,没有选择正确的行。

您的问题是您使用的是“结构”。解决您的问题的简单方法是让您的 struct 成为 class

public class MainLogData 
{ 
    public string Timestamp { get; set; } 
    public string Level { get; set; } 
    public string Message { get; set; } 
}

只需将 struct 字改为 class 即可解决您的问题。

你必须明白结构体和类是不一样的,结构体根据它们中的值(特定的2个变量)确定它们与另一个变量(具有相同类型)的“相等性”包含相同数据的结构类型将被视为相等)。在classes的情况下,除非另有说明,相等性由其内存地址决定;这确保了默认情况下,即使它们包含相同的数据,对象的任何 2 个实例都不会被视为相等,因为它们不位于相同的内存地址(此行为可以通过覆盖 "GetHashCode" 和 "Equals" 方法来覆盖在任何类定义中)。

因此,总而言之,DataGrid 在确定您正在选择哪个项目(或使用箭头键移动)时​​存在问题,因为列表中的许多对象被认为是“相同的”或“相等的”。这就是为什么它会感到困惑。诚然,我认为这是一个数据网格错误(或者至少是设计使然的奇怪行为),但是将数据类型从结构更改为类应该可以帮助您重回正轨!

干杯

【讨论】:

  • 感谢您的提示 -- 我会调查一下并通知您!
  • 我用我要显示的结构的定义更新了我的 OP。
  • +1。如果您想了解ValueType.GetHashCode 的工作原理,我建议您阅读this question。此外,结构应该是不可变的(即private set)。更多解释请看这里:Why are mutable structs evil
  • 谢谢,我会立即研究所有这些建议。
  • 有趣...看起来有一个通过代码隐藏添加的转换器,并且转换器的Convert 方法失败,因为它无法将value 参数转换为@987654328 @。有趣的是——如果MainLogData 被定义为一个结构,那么传递给IValueConverter.Convert 的value 对象的类型是MainLogData。如果我将它声明为一个类,那么value 的类型为NewItemPlaceholder。无论如何,我稍后会阅读 - 当演员表失败时返回 null 似乎有效,并且日志现在工作得很好!谢谢!
最近更新 更多