WPF DataGrid单元通过转换器时随机突出显示

时间:2014-08-14 16:32:18

标签: c# wpf xaml datagrid

我试图在用户输入的文本框中突出显示以给定值开头的所有单元格。我看了几个例子,生成了以下代码,这些代码有效,直到你开始垂直滚动。

首先我们有XAML,它使用多重绑定:

<DataGrid.CellStyle>
    <Style TargetType="{x:Type DataGridCell}">
        <Setter Property="Background">
            <Setter.Value>
                <MultiBinding Converter="{StaticResource CellColor}">
                    <Binding RelativeSource="{RelativeSource Mode=Self}"/>
                    <Binding Mode="OneWay" ElementName="contactFilterTextBox" Path="Text"/>
                </MultiBinding>
            </Setter.Value>
        </Setter>
    </Style>
</DataGrid.CellStyle>

接下来是我创建的类,它继承自IMultiValueConverter类:

public class ColorBasedOnFilterConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        System.Windows.Media.SolidColorBrush cellColor = Brushes.White;
        DataGridCell cellToAnalyze = (DataGridCell)values[0];
        TextBlock cellContents = (TextBlock)cellToAnalyze.Content;
        if (cellContents != null)
        {
            string cellValue = (string)cellContents.Text;
            string filterValue = values[1].ToString();
            if (!(String.IsNullOrEmpty(filterValue)))
            {
                if (cellValue.ToUpper().StartsWith(filterValue.ToUpper()))
                {
                    cellColor = Brushes.LightSalmon;
                }
            }
        }
        return cellColor;
    }
    public object[] ConvertBack(
        object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

最初,它按照我的预期工作,如下所示:Appropriate color classification by filter.

问题是当我滚动时,显然选择的值如下图所示?Inappropriate color classification by filter.

我对WPF很新,当然我做错了什么,但我对它是什么感到困惑。任何帮助都将非常感激。

2 个答案:

答案 0 :(得分:2)

默认情况下, Virtualizing 为dataGrid启用,这意味着容器即只为可见项生成DataGridRow。

VirtualizationMode 的默认值为 Recycling ,这意味着滚动时,已移出焦点的单元格将用于托管新的可见项目,这就是为什么您看到不正确的项目被着色的原因,因为它可能使用了相同的行。

要解决此问题,您可以 将VirtualizationMode设置为标准 ,以便始终生成新行来托管新的可见项。

<DataGrid VirtualizingStackPanel.VirtualizationMode="Standard">
   .......
</DataGrid>

答案 1 :(得分:0)

在我的(公认非常有限的)经验中,由于RowVirtualization,在CodeBehind中更改DataGridCell的属性通常会出错。我尽可能地避免瘟疫。改变单元格的背景颜色将是属于该类别的一个很好的例子。

替代(可以说是更好)选项可能是根本不设置CodeBehind中的颜色,而是使用DependencyProperty来确定单元格是否与条件匹配,然后使用Trigger设置背景颜色(或其他) 。你可以更全面地了解我在this answer所谈论的内容以及从this answer到我最近提出的问题的更多可能有用的信息,特别是如果你想“找到”所有问题如果没有虚拟化突出显示的单元格。这里的代码摘录与原始问题的目标非常相似,可以帮助您入门(主要是它只是根据提供的链接调整代码),以防有时帮助某人。

的Xaml:

<DataGrid local:DataGridTextSearch.SearchValue="{Binding ElementName=txtSearch, Path=Text, UpdateSourceTrigger=PropertyChanged}">
<DataGrid.Resources>
<local:SearchValueConverter x:Key="SearchValueConverter"/>
<Style TargetType="{x:Type DataGridCell}">
    <Setter Property="local:DataGridTextSearch.IsTextMatch">
        <Setter.Value>
            <MultiBinding Converter="{StaticResource SearchValueConverter}">
                <Binding RelativeSource="{RelativeSource Self}" Path="Content.Text" />
                <Binding RelativeSource="{RelativeSource Self}" Path="(local:DataGridTextSearch.SearchValue)" />
            </MultiBinding>
        </Setter.Value>
    </Setter>
    <Style.Triggers>
        <Trigger Property="local:DataGridTextSearch.IsTextMatch" Value="True">
            <Setter Property="Background" Value="Orange" />
            <Setter Property="Tag" Value="1" />
        </Trigger>
    </Style.Triggers>
</Style>
</DataGrid.Resources>
</DataGrid>

DependencyProperty:

Public NotInheritable Class DataGridTextSearch
Private Sub New()
End Sub
Public Shared ReadOnly SearchValueProperty As DependencyProperty = DependencyProperty.RegisterAttached("SearchValue", GetType(String), GetType(DataGridTextSearch), New FrameworkPropertyMetadata(String.Empty, FrameworkPropertyMetadataOptions.[Inherits]))
Public Shared Function GetSearchValue(obj As DependencyObject) As String
    Return DirectCast(obj.GetValue(SearchValueProperty), String)
End Function
Public Shared Sub SetSearchValue(obj As DependencyObject, value As String)
    obj.SetValue(SearchValueProperty, value)
End Sub
Public Shared ReadOnly IsTextMatchProperty As DependencyProperty = DependencyProperty.RegisterAttached("IsTextMatch", GetType(Boolean), GetType(DataGridTextSearch), New UIPropertyMetadata(False))
Public Shared Function GetIsTextMatch(obj As DependencyObject) As Boolean
    Return CBool(obj.GetValue(IsTextMatchProperty))
End Function
Public Shared Sub SetIsTextMatch(obj As DependencyObject, value As Boolean)
    obj.SetValue(IsTextMatchProperty, value)
End Sub
End Class

转换器(这肯定可以充实,但你明白了):

Public Class SearchValueConverter
Implements IMultiValueConverter
Public Function Convert(values() As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IMultiValueConverter.Convert
    Dim cellText As String = If(values(0) Is Nothing, String.Empty, values(0).ToString())
    Dim searchText As String = TryCast(values(1), String)

    If Not String.IsNullOrEmpty(searchText) AndAlso Not String.IsNullOrEmpty(cellText) Then
        If cellText.ToLower().Contains(searchText.ToLower()) Then
            Return True 
        Else
            Return False
        End If
    End If
    Return False
End Function
Public Function ConvertBack(value As Object, targetTypes() As Type, parameter As Object, culture As Globalization.CultureInfo) As Object() Implements IMultiValueConverter.ConvertBack
    Return Nothing
End Function
End Class