在WPF DataGrid中的LoadingRow事件上交替显示行颜色 [英] Alternating row colors on LoadingRow event in WPF DataGrid doubling colors on rows

查看:73
本文介绍了在WPF DataGrid中的LoadingRow事件上交替显示行颜色的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过LoadingRow事件以编程方式交替显示行颜色.这样做的原因是因为我需要在某些行上指定一种特定的颜色,即标记为要删除的行和具有修改后的数据的行.

I am alternating row colors programatically through the LoadingRow event. The reason for this is because I need to specify a specific color on some rows, i.e. rows marked for deletion and rows with modified data.

这很好用,直到我在DataGrid中向上滚动并且得到这种非常奇怪的交互作用,它将行颜色加倍或增加三倍.

This works fine, until I scroll up in the DataGrid and I get this very weird interaction where it doubles or triples up the row colors.

向下滚动时正确显示.

我尝试使用AlternateIndex并将AlternateCount设置为2,并使用布尔值在两者之间进行切换,这都会导致完全相同的问题.

I have tried using AlternationIndex with AlternationCount set to 2, and using a bool to flip between, both result in the exact same issue.

如果我没有在LoadingRow事件中设置此项,而是使用DataGrid AlternatingRowBackground,则当我在表格中滚动时,该行的颜色会渗入其他行.

If I dont set this in the LoadingRow event and use the DataGrid AlternatingRowBackground the row color bleeds into other rows as I scroll through the table.

private void dataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
        {
            // Get the DataRow corresponding to the DataGridRow that is loading.
            var item = e.Row.Item as ExpandoObject;
            if (loadedTable.ToDelete.Contains(item))
            {
                e.Row.Background = new SolidColorBrush(Colors.OrangeRed);
                return;
            }
            else if (loadedTable.Modified.Contains(loadedTable.Rows.IndexOf(item)))
            {
                e.Row.Background = new SolidColorBrush(Colors.LightYellow);
                return;
            }
            else if (e.Row.AlternationIndex == 0)
            {
                e.Row.Background = new SolidColorBrush(Colors.WhiteSmoke);
            }
            else if (e.Row.AlternationIndex == 1)
            {
                e.Row.Background = new SolidColorBrush(Colors.LightGray);
            }
        }

<DataGrid CanUserAddRows="False" GridLinesVisibility="All" VerticalGridLinesBrush="Gray" HorizontalGridLinesBrush="Gray"
                                 FontSize="15" FrozenColumnCount ="1" x:Name="xmlData" EnableRowVirtualization="True" AlternationCount="1"
                                 AlternatingRowBackground="LightGray" Background="WhiteSmoke"
                                 Grid.Column="1" Margin="0,-31,5,10" AutoGenerateColumns="False" Grid.Row="2" SelectionUnit="Cell" 
                                 PreviewKeyDown="DataGridKeyDown_Event" IsReadOnly="True" CanUserDeleteRows="True"
                                 LoadingRow="dataGrid_LoadingRow"/>

推荐答案

您遇到的问题是因为DataGrid重用了DataGridRow对象(可以尝试EnableRowVirtualization ="False").

The problem you're having is because DataGrid reuses DataGridRow objects (could try EnableRowVirtualization="False").

您要做的是使用样式根据数据/项目设置DataGridRow的背景.

What you want to do is set the DataGridRow's background based on it's data/item using styles.

这是一个测试应用程序,可以完成您想做的事情.

Here is a test app that does what you want to do.

XAML

<Window x:Class="WpfApp9.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApp9"
    mc:Ignorable="d"
    Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
    <local:VM />
</Window.DataContext>
<Grid>
    <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding Items}" AlternationCount="2">
        <DataGrid.Resources>
            <!-- Converter used to convert the DataRow's Item and the VM.ToDelete list to bool (true = it is deleted) -->
            <local:IsDeletedConverter x:Key="IsDeletedConverter" />
        </DataGrid.Resources>
        <DataGrid.RowStyle>
            <Style TargetType="DataGridRow">
                <Style.Triggers>
                    <!-- Setup the background color for normal rows using AlternationIndex -->
                    <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                        <Setter Property="Background" Value="WhiteSmoke" />
                    </Trigger>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                        <Setter Property="Background" Value="LightGray" />
                    </Trigger>
                    <!-- Override the above background colors if it is in the deleted list - NOTE: these styles are processed in order, make sure this is after the above triggers -->
                    <DataTrigger Value="True">
                        <DataTrigger.Binding>
                            <MultiBinding Converter="{StaticResource IsDeletedConverter}">
                                <!-- This is the DataContext of the DataGridRow - the item (ExpandoObject) we will check for in the deleted list -->
                                <Binding />
                                <!-- Need the deleted list, which is in VM -->
                                <Binding RelativeSource="{RelativeSource AncestorType=Window}" Path="DataContext" />
                            </MultiBinding>
                        </DataTrigger.Binding>
                        <DataTrigger.Setters>
                            <Setter Property="Background" Value="OrangeRed" />
                        </DataTrigger.Setters>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </DataGrid.RowStyle>
        <DataGrid.Columns>
            <DataGridTextColumn Header="Col1" Binding="{Binding Col1}" />
            <DataGridTextColumn Header="Col2" Binding="{Binding Col2}" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>

CODE

using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace WpfApp9
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
    }

    public class VM
    {
        public List<System.Dynamic.ExpandoObject> Items { get; set; }
        public List<System.Dynamic.ExpandoObject> ToDelete { get; set; }

        public VM()
        {
            Items = new List<System.Dynamic.ExpandoObject>();
            ToDelete = new List<System.Dynamic.ExpandoObject>();

            for (int i = 0; i < 1000; i++)
            {
                var eo = new System.Dynamic.ExpandoObject();
                var d = eo as IDictionary<string, object>;
                d["Col1"] = $"String {i}";
                d["Col2"] = i;
                Items.Add(eo);

                // Add some items to ToDelete list
                if (i % 10 == 0)
                {
                    ToDelete.Add(eo);
                }
            }
        }
    }

    public class IsDeletedConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            if (values.Length != 2)
                throw new ArgumentException($"IsDeletedConverter is expecting 2 values but got {values.Length} values!", nameof(values));

            if (values[0] is System.Dynamic.ExpandoObject eo && values[1] is VM vm)
            {
                if (vm.ToDelete.Contains(eo))
                    return true;
            }
            return false;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

这篇关于在WPF DataGrid中的LoadingRow事件上交替显示行颜色的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆