WPF DataGrid - 单个单元格上的条件格式触发器

时间:2016-03-01 14:10:37

标签: wpf vb.net xaml datagrid styles

我需要让我的DataGrid中的单元格反映条件规则......我已经到目前为止已经花了太多时间在这上面我希望有人可以帮助我吗?所以,这就是我的网格在运行时的当前状态:

enter image description here

在这里,您可以看到(忽略结果& 标准列),这里有三组两列需要关注。我目前正在将条件规则应用于 XPercVerified 列,但最终我希望 EF [X] 列根据相应PercVerified列中的值显示背景更改。另一个要点是,可以有任意数量的这两个列组合......

我目前遇到的问题是,我似乎只能应用规则来有条件地格式化整个Row。在上面的屏幕截图中,您可以看到 1PercVerified 列在第一行中有一个..这使整行变为绿色。代码如下:

Private Sub dgUnitMatrix_AutoGeneratingColumn(sender As Object, e As DataGridAutoGeneratingColumnEventArgs) Handles dgUnitMatrix.AutoGeneratingColumn

    If (e.Column.Header.ToString().Contains("PercVerified")) Then

        e.Column.CellStyle = TryCast(Application.Current.FindResource("PercVerified"), Style)

    End If

End Sub

我们在这里调用 AutoGeneratingColumn 事件,当我们有一个 PercVerified 的列时,请调用应用程序资源样式:

<Application x:Class="Application"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml"
ShutdownMode="OnMainWindowClose">

    <Application.Resources>

        <Style x:Key="PercVerified" TargetType="{x:Type DataGridCell}" >
            <Style.Triggers>
                <DataTrigger Binding="{Binding 1PercVerified}" Value="0">
                    <Setter Property="Background" Value="DarkRed"></Setter>
                    <Setter Property="Foreground" Value="White"></Setter>
                    <Setter Property="Margin" Value="-2.0"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding 1PercVerified}" Value="1">
                    <Setter Property="Background" Value="DarkGreen"></Setter>
                    <Setter Property="Foreground" Value="White"></Setter>
                    <Setter Property="Margin" Value="-2.0"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>

    </Application.Resources>
</Application>

Application.XAML 文件中存在。 我似乎有的另一个问题是,即使我可以让上述工作只在单元格(而不是行) - 我似乎只能在我的条件下确定(即绑定值必须相等 - 我不能做整数大于或小于?)...这是真的吗?

我已经开始向更远的地方看,因为我得到的印象是这种造型不适用于我想要的东西......所以,IValueConverters已经出现了几次,但我似乎无法获得这工作。是否值得我花时间研究这些只是为了发现它是另一个死胡同?

我可以提供任何人可能需要的任何额外信息......我非常渴望将其排序,因为我已经浪费了太多时间在WPF中的某些东西,这在Winforms中只是很容易!

修改

遵循J.H.的优秀答案。我已经使用作为对象值传递的DataRowView(而不是示例类对象)将其调整为wor。

在转换器中,我们正在创建变量dc。整个代码块已更改为:

    ' Get the cells DataContext as our data class '
    Dim dc As DataRowView
    dc = TryCast(cell.DataContext, DataRowView)
    If IsNothing(dc) Then Exit Function

    ' Get the column number of the columnName that matches the Path 
    Dim ColNo As Integer
    Dim idx As Integer = 0
    For Each column As DataColumn In dc.DataView.Table.Columns
        If column.ColumnName = path Then
            ColNo = idx
        End If
        idx = idx + 1
    Next

然后在进行条件格式的比较而不是:

Dim pv = dc.GetType().GetProperty(path).GetValue(dc)

我们使用

Dim pv As String = dc.Row.Item(ColNo).ToString()

除了由于差异而导致的一些其他变化之外,这也是一种享受!

1 个答案:

答案 0 :(得分:1)

您可以使用IValueConverter执行此操作。您需要将DataGridCell传递给转换器。从单元格中,您可以获得datacontext和单元格的绑定。一旦你有了这些,一些反射可以获得PercVerifiedX字段的值。您可以检测EFX字段,然后获取适当的PercVerifiedX字段。

以下是一些代码,请注意我的属性名称与您的属性名称不同(无法使用数字启动属性),因此您可能需要调整一些代码。此外,我可以使用数字,但为DataTrigger.Value选择字符串只是为了表明它不是PercVerified值而是转换器的返回值。 并且,我把它混合了一点 - 红色为0 percs,绿色为1-3 percs,紫色为4+ percs。请参阅xaml和转换器的代码。

XAML

<Window x:Class="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:WpfApplication16"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525">
    <Window.Resources>
        <local:PercVerifiedConverter x:Key="PercVerifiedConverter" />
        <Style x:Key="PercVerified" TargetType="{x:Type DataGridCell}" >
            <Style.Triggers>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource PercVerifiedConverter}}" Value="Red">
                    <Setter Property="Background" Value="DarkRed"></Setter>
                    <Setter Property="Foreground" Value="White"></Setter>
                    <Setter Property="Margin" Value="-2.0"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource PercVerifiedConverter}}" Value="Green">
                    <Setter Property="Background" Value="DarkGreen"></Setter>
                    <Setter Property="Foreground" Value="White"></Setter>
                    <Setter Property="Margin" Value="-2.0"></Setter>
                </DataTrigger>
                <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Converter={StaticResource PercVerifiedConverter}}" Value="Purple">
                    <Setter Property="Background" Value="Purple"></Setter>
                    <Setter Property="Foreground" Value="Yellow"></Setter>
                    <Setter Property="Margin" Value="-2.0"></Setter>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>
    <DataGrid ItemsSource="{Binding Data}" AutoGeneratingColumn="DataGrid_AutoGeneratingColumn" />
</Window>

.VB(带有评论的PITA是什么让颜色编码正确)

Imports System.Globalization

Class MainWindow
    Public Sub New()
        ' This call is required by the designer. '
        InitializeComponent()

        Dim vm As New VM
        vm.Data = New List(Of MyData) From {
                New MyData() With {.Outcome = "Outcome 1", .Criterion = "1.1", .PercVerified1 = 1, .EF1 = "EP, ECH", .PercVerified3 = 0, .EF3 = "", .PercVerified4 = 0, .EF4 = "EWT"},
                New MyData() With {.Outcome = "", .Criterion = "1.2", .PercVerified1 = 0, .EF1 = "", .PercVerified3 = 1, .EF3 = "O, EP", .PercVerified4 = 0, .EF4 = ""},
                New MyData() With {.Outcome = "", .Criterion = "1.3", .PercVerified1 = 0, .EF1 = "", .PercVerified3 = 0, .EF3 = "O, EP", .PercVerified4 = 4, .EF4 = ""}
            }
        Me.DataContext = vm
    End Sub

    Private Sub DataGrid_AutoGeneratingColumn(sender As Object, e As DataGridAutoGeneratingColumnEventArgs)
        If (e.Column.Header.ToString().Contains("PercVerified") Or e.Column.Header.ToString().Contains("EF")) Then
            e.Column.CellStyle = TryCast(Me.FindResource("PercVerified"), Style)
        End If
    End Sub
End Class

Public Class MyData
    Public Property Outcome As String
    Public Property Criterion As String
    Public Property PercVerified1 As String
    Public Property EF1 As String
    Public Property PercVerified3 As String
    Public Property EF3 As String
    Public Property PercVerified4 As String
    Public Property EF4 As String
End Class

Public Class VM
    Public Property Data As List(Of MyData)
End Class

Public Class PercVerifiedConverter
    Implements IValueConverter

    Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.Convert
        Convert = Nothing
        Dim cell As DataGridCell
        Dim dc As MyData

        ' Get the DataGridCell passed in '
        cell = TryCast(value, DataGridCell)
        If IsNothing(cell) Then Exit Function

        ' Get the cells DataContext as our data class '
        dc = TryCast(cell.DataContext, MyData)
        If IsNothing(dc) Then Exit Function

        ' Get the cells column - need it for the binding '
        Dim tc As DataGridTextColumn ' Assuming your cells are DataGridTextColumns '
        tc = TryCast(cell.Column, DataGridTextColumn)
        If IsNothing(tc) Then Exit Function

        ' Get the columns binding '
        Dim b As Binding
        b = TryCast(tc.Binding, System.Windows.Data.Binding)
        If IsNothing(b) Then Exit Function

        ' Get the path off the binding '
        Dim path As String
        path = b.Path.Path ' Name of the property this column is bound to - PercVerified1, EF1, etc... '

        ' If one of the "EF" properties, convert path to the appropriate "PercVerified" path '
        If path.Contains("EF") Then
            Dim pvNum = path.Replace("EF", String.Empty) ' EF1 becomes 1 '
            path = "PercVerified" + pvNum ' path is now PercVerified1 '
        End If
        If path.Contains("PercVerified") Then
            Dim pv = dc.GetType().GetProperty(path).GetValue(dc)
            If pv = 0 Then
                Convert = "Red"
            ElseIf pv >= 1 And pv <= 3 Then
                Convert = "Green"
            ElseIf pv >= 4 Then
                Convert = "Purple"
            End If
        End If
    End Function

    Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As CultureInfo) As Object Implements IValueConverter.ConvertBack
        Throw New NotImplementedException()
    End Function
End Class

并且,截图:

enter image description here