滚动后 WPF Datagrid 工具包列未正确绘制 down/up
WPF Datagrid toolkit columns not painting correctly after scrolling down/up
我有一个 WPF MVVM 应用程序。在主 WPF Window 中,我有一个 WPF Datagrid 工具包。
这个数据网格有一些列。根据某些条件(绑定在视图模型上的属性),颜色将应用于整行。
此外还有两个特殊列。这两列的类型为 DataGridTextColumn,称为 Date1 和 Date2。
如果 Date1 值大于 Date2 值,Date1 和 Date2 单元格都应使用橙红色着色。
分别绑定到 MyDate1 和 MyDate2 视图模型属性的 Date1 和 Date2 属于 DateTime 类型。
我的问题是:
首先,当数据网格加载数据时,行以及 Date1 和 Date2 列的颜色正确。
由于 Date1 > Date2,某些行显示为 Date1 和 Date2,颜色为橙红色。
然后,如果我使用垂直滚动条向下滚动数据网格,然后再次向上滚动到第一个数据网格行,我注意到现在有更多行(Date1 和 Date2 列)
尽管 Date1 <= Date2.
发生了什么事?
查看:
<Window x:Name="MainWindow" x:Class="My.Apps.WPF.TestApp.wMain"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit"
xmlns:classes="clr-namespace:My.Apps.WPF.TestApp.Classes"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
WindowState="Maximized">
<Grid x:Name="MyGrid" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<my:DataGrid Grid.Row="1" Name="MyDg"
AutoGenerateColumns="False"
ItemsSource="{Binding Path=MyListOfItems}"
SelectedItem="{Binding Path=MySelectedItem}"
VerticalAlignment="Stretch" IsReadOnly="True"
SelectionMode="Single" ColumnWidth="*"
SelectionChanged="MyDg_SelectionChanged"
Width="{Binding Path=ActualWidth, ElementName=MyGrid}">
<my:DataGrid.Resources>
<classes:BindingProxy x:Key="proxy" Data="{Binding}" />
<Style x:Key="MyDataGridCellStyle" TargetType="{x:Type my:DataGridCell}" BasedOn="{StaticResource {x:Type my:DataGridCell}}">
<!-- If Date1 > Date2 apply background color -->
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource CellDateColorConverter}">
<Binding Path="MyDate1"/> <!-- Date1 value -->
<Binding Path="MyDate2"/> <!-- Date2 value -->
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</my:DataGrid.Resources>
<my:DataGrid.RowStyle>
<!-- Style for entire datagrid row -->
<Style TargetType="my:DataGridRow">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=GroupID, Converter={StaticResource IdGroupConverter}}" Value="True" />
<Condition Binding="{Binding Path=MyFlag}" Value="0" />
<Condition Binding="{Binding Path=StatusFilter, Converter={StaticResource StatusFilterConverter}}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="#FFAC62"></Setter>
</MultiDataTrigger>
<DataTrigger Binding="{Binding Path=MyFlag}}" Value="1">
<Setter Property="Background" Value="{Binding DeniedColor}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=MyFlag}" Value="2">
<Setter Property="Background" Value="{Binding PendingColor}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</my:DataGrid.RowStyle>
<my:DataGrid.Columns>
<my:DataGridTextColumn x:Name="Date1"
CellStyle="{StaticResource MyDataGridCellStyle}"
Binding="{Binding Path=MyDate1, StringFormat=\{0:dd/MM/yyyy\}}"
Header="Date 1"
Width="{Binding DataComandaColWidth, Source={StaticResource DO}, Mode=TwoWay}"
HeaderStyle="{DynamicResource CenterGridHeaderStyle}">
<my:DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Margin" Value="5 0"/>
</Style>
</my:DataGridTextColumn.ElementStyle>
</my:DataGridTextColumn>
<my:DataGridTextColumn x:Name="Date2"
CellStyle="{StaticResource MyDataGridCellStyle}"
Binding="{Binding Path=MyDate2, StringFormat=\{0:dd/MM/yyyy\}}"
Header="Date 2"
Width="auto"
HeaderStyle="{DynamicResource CenterGridHeaderStyle}">
<my:DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Margin" Value="5 0"/>
</Style>
</my:DataGridTextColumn.ElementStyle>
</my:DataGridTextColumn>
</my:DataGrid.Columns>
</my:DataGrid>
</Grid>
</Window>
类:
namespace My.Apps.WPF.TestApp.Classes
{
public class CellDateColorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values[0] is DateTime && values[1] is DateTime)
{
DateTime date1 = (DateTime)values[0];
DateTime date2 = (DateTime)values[1];
if (date1.Date > date2.Date)
{
return System.Windows.Media.Brushes.OrangeRed;
}
}
return System.Windows.Data.Binding.DoNothing;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("CellDateColorConverter is a OneWay converter.");
}
}
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}
}
我已经通过将 EnableRowVirtualization 设置为 False 来解决了。它默认设置为 True。 属性 EnableColumnVirtualization 默认设置为 False。
似乎使用虚拟化单元会影响 .NET 3.5 中的数据网格样式。漏洞?如果是这样,不知道在NET 4.0及以上版本中是否已经修正
无论如何,我很担心,因为这意味着我无法使用虚拟化单元...所以如果有人有任何其他解决方案,请在这里分享。
其他用户遇到过同样的问题,见here
已更新:
另外,如果你想保留 EnableRowVirtualization 为 True,只需更改虚拟化模式即可解决:
<DataGrid VirtualizingStackPanel.VirtualizationMode="Standard" />
问题是 VirtualizationMode 默认设置为 Recycling,因此当容器被重复使用时,这会导致滚动时不正确的行着色。 Eirik 在他的回答中对此进行了解释 here。
我有一个 WPF MVVM 应用程序。在主 WPF Window 中,我有一个 WPF Datagrid 工具包。 这个数据网格有一些列。根据某些条件(绑定在视图模型上的属性),颜色将应用于整行。 此外还有两个特殊列。这两列的类型为 DataGridTextColumn,称为 Date1 和 Date2。 如果 Date1 值大于 Date2 值,Date1 和 Date2 单元格都应使用橙红色着色。 分别绑定到 MyDate1 和 MyDate2 视图模型属性的 Date1 和 Date2 属于 DateTime 类型。
我的问题是: 首先,当数据网格加载数据时,行以及 Date1 和 Date2 列的颜色正确。 由于 Date1 > Date2,某些行显示为 Date1 和 Date2,颜色为橙红色。 然后,如果我使用垂直滚动条向下滚动数据网格,然后再次向上滚动到第一个数据网格行,我注意到现在有更多行(Date1 和 Date2 列) 尽管 Date1 <= Date2.
发生了什么事?
查看:
<Window x:Name="MainWindow" x:Class="My.Apps.WPF.TestApp.wMain"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit"
xmlns:classes="clr-namespace:My.Apps.WPF.TestApp.Classes"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
WindowState="Maximized">
<Grid x:Name="MyGrid" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="auto"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="auto"></RowDefinition>
</Grid.RowDefinitions>
<my:DataGrid Grid.Row="1" Name="MyDg"
AutoGenerateColumns="False"
ItemsSource="{Binding Path=MyListOfItems}"
SelectedItem="{Binding Path=MySelectedItem}"
VerticalAlignment="Stretch" IsReadOnly="True"
SelectionMode="Single" ColumnWidth="*"
SelectionChanged="MyDg_SelectionChanged"
Width="{Binding Path=ActualWidth, ElementName=MyGrid}">
<my:DataGrid.Resources>
<classes:BindingProxy x:Key="proxy" Data="{Binding}" />
<Style x:Key="MyDataGridCellStyle" TargetType="{x:Type my:DataGridCell}" BasedOn="{StaticResource {x:Type my:DataGridCell}}">
<!-- If Date1 > Date2 apply background color -->
<Setter Property="Background">
<Setter.Value>
<MultiBinding Converter="{StaticResource CellDateColorConverter}">
<Binding Path="MyDate1"/> <!-- Date1 value -->
<Binding Path="MyDate2"/> <!-- Date2 value -->
</MultiBinding>
</Setter.Value>
</Setter>
</Style>
</my:DataGrid.Resources>
<my:DataGrid.RowStyle>
<!-- Style for entire datagrid row -->
<Style TargetType="my:DataGridRow">
<Style.Triggers>
<MultiDataTrigger>
<MultiDataTrigger.Conditions>
<Condition Binding="{Binding Path=GroupID, Converter={StaticResource IdGroupConverter}}" Value="True" />
<Condition Binding="{Binding Path=MyFlag}" Value="0" />
<Condition Binding="{Binding Path=StatusFilter, Converter={StaticResource StatusFilterConverter}}" Value="True"/>
</MultiDataTrigger.Conditions>
<Setter Property="Background" Value="#FFAC62"></Setter>
</MultiDataTrigger>
<DataTrigger Binding="{Binding Path=MyFlag}}" Value="1">
<Setter Property="Background" Value="{Binding DeniedColor}"></Setter>
</DataTrigger>
<DataTrigger Binding="{Binding Path=MyFlag}" Value="2">
<Setter Property="Background" Value="{Binding PendingColor}"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</my:DataGrid.RowStyle>
<my:DataGrid.Columns>
<my:DataGridTextColumn x:Name="Date1"
CellStyle="{StaticResource MyDataGridCellStyle}"
Binding="{Binding Path=MyDate1, StringFormat=\{0:dd/MM/yyyy\}}"
Header="Date 1"
Width="{Binding DataComandaColWidth, Source={StaticResource DO}, Mode=TwoWay}"
HeaderStyle="{DynamicResource CenterGridHeaderStyle}">
<my:DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Margin" Value="5 0"/>
</Style>
</my:DataGridTextColumn.ElementStyle>
</my:DataGridTextColumn>
<my:DataGridTextColumn x:Name="Date2"
CellStyle="{StaticResource MyDataGridCellStyle}"
Binding="{Binding Path=MyDate2, StringFormat=\{0:dd/MM/yyyy\}}"
Header="Date 2"
Width="auto"
HeaderStyle="{DynamicResource CenterGridHeaderStyle}">
<my:DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
<Setter Property="Margin" Value="5 0"/>
</Style>
</my:DataGridTextColumn.ElementStyle>
</my:DataGridTextColumn>
</my:DataGrid.Columns>
</my:DataGrid>
</Grid>
</Window>
类:
namespace My.Apps.WPF.TestApp.Classes
{
public class CellDateColorConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
if (values[0] is DateTime && values[1] is DateTime)
{
DateTime date1 = (DateTime)values[0];
DateTime date2 = (DateTime)values[1];
if (date1.Date > date2.Date)
{
return System.Windows.Media.Brushes.OrangeRed;
}
}
return System.Windows.Data.Binding.DoNothing;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotSupportedException("CellDateColorConverter is a OneWay converter.");
}
}
public class BindingProxy : Freezable
{
#region Overrides of Freezable
protected override Freezable CreateInstanceCore()
{
return new BindingProxy();
}
#endregion
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
// Using a DependencyProperty as the backing store for Data. This enables animation, styling, binding, etc...
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(BindingProxy), new UIPropertyMetadata(null));
}
}
我已经通过将 EnableRowVirtualization 设置为 False 来解决了。它默认设置为 True。 属性 EnableColumnVirtualization 默认设置为 False。
似乎使用虚拟化单元会影响 .NET 3.5 中的数据网格样式。漏洞?如果是这样,不知道在NET 4.0及以上版本中是否已经修正
无论如何,我很担心,因为这意味着我无法使用虚拟化单元...所以如果有人有任何其他解决方案,请在这里分享。
其他用户遇到过同样的问题,见here
已更新:
另外,如果你想保留 EnableRowVirtualization 为 True,只需更改虚拟化模式即可解决:
<DataGrid VirtualizingStackPanel.VirtualizationMode="Standard" />
问题是 VirtualizationMode 默认设置为 Recycling,因此当容器被重复使用时,这会导致滚动时不正确的行着色。 Eirik 在他的回答中对此进行了解释 here。