在WPF DataGrid中的LoadingRow事件上交替显示行颜色 [英] Alternating row colors on LoadingRow event in WPF DataGrid doubling colors on rows
问题描述
我正在通过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屋!