【问题标题】:Cell color is reset in virtualized data grid in WPF在 WPF 中的虚拟化数据网格中重置单元格颜色
【发布时间】:2018-07-24 13:39:53
【问题描述】:

我有一个简单的 WPF 应用程序,它在数据网格中显示大约 30-35,000 行数据,如果用户更改任何单元格值,则应通过更改其背景颜色突出显示该单元格。列在运行时根据数据生成。鉴于它拥有的数据量,虚拟化数据网格是必须的。这是我的数据网格:

<DataGrid x:Name="dgPropertyData" HeadersVisibility="Column" ColumnHeaderHeight="25" 
                  BorderThickness="0" AutoGenerateColumns="false" 
                  HorizontalGridLinesBrush="#FFC7C5C5" 
                  VerticalGridLinesBrush="#FFC7C5C5" 
                  MinRowHeight="20" CanUserResizeRows="False" 
                  CanUserDeleteRows="False" CanUserReorderColumns="False" 
                  EnableRowVirtualization="true" 
                  AutoGeneratedColumns="dgPropertyData_AutoGeneratedColumns"                      
                  CellEditEnding="dgPropertyData_CellEditEnding">
            <DataGrid.ColumnHeaderStyle>
                <Style TargetType="{x:Type DataGridColumnHeader}">
                    <Setter Property="FontWeight" Value="Bold"/>
                </Style>
            </DataGrid.ColumnHeaderStyle>
        </DataGrid>

我正在代码隐藏方法中更改单元格背景颜色:

    private void dgPropertyData_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
    {
        string oldValue = (e.Row.Item as BindableDynamicDictionary)[e.Column.Header as string] as string;
        string newValue = (e.EditingElement as System.Windows.Controls.TextBox).Text;

        if ((oldValue != null && oldValue.CompareTo(newValue) != 0) || (oldValue == null && string.IsNullOrEmpty(newValue) == false))
        {         
            (e.Column.GetCellContent(e.Row).Parent as DataGridCell).Background = Brushes.Orange;
            IsCellEdited = true;
        }
    }

我的问题:当我编辑一个单元格时,背景会很好地变化以通知值已更改。直到......我滚动网格视图。滚动时, 已编辑的单元格被擦除,错误的单元格被绘制(如果有的话)。

我通过以下问题得到了一些想法:

  1. Changing color of a single cell in WPF Datagrid
  2. Wpf Datagrid Virtualization Issue when setting cell colors
  3. RowVirtualization cause incorrect background color for rows

但是还没有找到适合我的目的的解决方案。作为 WPF 世界的新手,我经常会思考如何解决这个问题。我知道丢失单元格背景颜色的问题是由于行的回收,如果我禁用虚拟化,性能损失对于我拥有的数据量是无法承受的。

【问题讨论】:

    标签: wpf datagrid wpfdatagrid


    【解决方案1】:

    您应该处理行视图模型中的逻辑,而不是在视图中处理 CellEditEnding 事件,在您的情况下这似乎是 BindableDynamicDictionary

    在值显示在单元格中的属性的设置器中,您可以进行比较(您当前在视图的代码隐藏中进行的比较)并设置IsCellEdited 属性以指示单元格是否已修改。

    然后,您应该在视图中使用CellStyleDataTrigger,该DataTrigger 绑定到此属性并根据其值更改单元格的背景颜色。

    这种设计模式被称为模型-视图-视图模型 (MVVM),它是开发基于 XAML 的 UI 应用程序时使用的推荐模式。有一个原因。你刚刚遇到了其中一个。这种逻辑不应该在视图中处理,正如您已经注意到的,如果您禁用 UI 虚拟化,它甚至都不会工作。

    【讨论】:

    • 谢谢@mm8,在使用 MVVM 方面非常同意您的 cmets。只是我仍在努力解决它。我猜,多年使用 WinForms 会杀死一些有助于您在 MVVM 中思考的脑细胞。
    【解决方案2】:

    正如我在原来的帖子中提到的,我对 WPF 和 MVVM 还是新手,所以我仍然会大量使用代码隐藏语言。有一天,我将在纯 XAML 中实现它。但在那之前,我想出了代码隐藏解决方案。我知道,很多人不会喜欢它,但这不仅仅是被卡住。

    我有一本字典来跟踪编辑过的单元格

    Dictionary<int, List<int>> editedCells = new Dictionary<int, List<int>>(); // Row No, List<Column No>
    

    我在更改背景时将编辑的单元格位置保存在此字典中:

        private void dgPropertyData_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
        {
            string oldValue = (e.Row.Item as BindableDynamicDictionary)[e.Column.Header as string] as string;
            string newValue = (e.EditingElement as System.Windows.Controls.TextBox).Text;
    
            if ((oldValue != null && oldValue.CompareTo(newValue) != 0) || (oldValue == null && string.IsNullOrEmpty(newValue) == false))
            {         
                (e.Column.GetCellContent(e.Row).Parent as DataGridCell).Background = Brushes.Orange;
                IsCellEdited = true;
    
                // Mark this cell has been edited.
                var columnIndex = e.Column.DisplayIndex;
                var rowIndex = dgPropertyData.Items.IndexOf(e.Row.Item);
    
                if (editedCells.ContainsKey(rowIndex) == false)
                    editedCells.Add(rowIndex, new List<int>());
    
                editedCells[rowIndex].Add(columnIndex);                                   
            }
        }
    

    当用户滚动数据网格时,一些行会被隐藏,一些会被显示。当一行被隐藏时,我清除已编辑的单元格背景,当显示时,我为已编辑的单元格重新着色。

        private void dgPropertyData_LoadingRow(object sender, DataGridRowEventArgs e)
        {
            var rowIndex = dgPropertyData.Items.IndexOf(e.Row.Item);
    
            if(editedCells.ContainsKey(rowIndex) == true)
            {
                editedCells[rowIndex].ForEach( columnIndex =>
                {
                    var column = dgPropertyData.Columns[columnIndex];
    
                    (column.GetCellContent(e.Row).Parent as DataGridCell).Background = Brushes.Orange;
    
                });                
            }
        }
    
        private void dgPropertyData_UnloadingRow(object sender, DataGridRowEventArgs e)
        {
            var rowIndex = dgPropertyData.Items.IndexOf(e.Row.Item);
    
            if (editedCells.ContainsKey(rowIndex) == true)
            {
                editedCells[rowIndex].ForEach(columnIndex =>
                {
                    var column = dgPropertyData.Columns[columnIndex];
    
                    (column.GetCellContent(e.Row).Parent as DataGridCell).ClearValue(DataGridCell.BackgroundProperty);
    
                });
            }
        }
    

    对我来说很好用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-04-17
      • 1970-01-01
      • 2012-09-30
      • 1970-01-01
      • 1970-01-01
      • 2019-01-28
      • 2017-01-06
      • 2022-01-06
      相关资源
      最近更新 更多