【问题标题】:Color a DataGrid row based on a DataTable value根据 DataTable 值为 DataGrid 行着色
【发布时间】:2016-12-21 16:39:09
【问题描述】:

我从 CSV 文件中提取数据,在 DataTable 中对其进行解析,然后将此 DataTable 设置为 DataGrid 的 ItemsSource。然后,我循环 DataTable 以对数据进行一些验证,并且我想相应地为 DataGrid 行着色。

问题是,我无法根据DataTable行找到对应的DataGrid行。

这是我的代码:

Dim dg As New DataGrid
Dim dataTable as DataTable = ParseFile(filePath)
Dim statutList() As String = {"Saisi", "Validé", "Suspendu", "Annulé"}

dg.ItemsSource = dataTable.DefaultView

For Each row As DataRow In dataTable.Rows
    'This line is what I tried, but it always returns nothing
    Dim dgrow As DataGridRow = dg.ItemContainerGenerator.ContainerFromItem(row)
    If Not statutList.Contains(row("Statut").ToString) Then
        dgrow.Background = Brushes.Red
    End If
Next

问题来自这一行,它不起作用:

Dim dgrow As DataGridRow = dg.ItemContainerGenerator.ContainerFromItem(row)

解决方案:

两种 mm8 解决方案都有效。就我而言,我使用了:

dg.UpdateLayout()
For Each row As DataRowView In dg.Items.OfType(Of DataRowView)
    Dim dgrow As DataGridRow = dg.ItemContainerGenerator.ContainerFromItem(row)
    If Not statutList.Contains(row("Statut").ToString) Then
        dgrow.Background = Brushes.Red
    End If
Next

【问题讨论】:

    标签: wpf vb.net


    【解决方案1】:

    正确的“WPF”方法是定义一个 RowStyle,其中包含一个或多个数据触发器,当该特定行的“Statut”列返回任何特定值时,设置该行的背景颜色,例如:

    <DataGrid x:Name="dg">
        <DataGrid.Resources>
            <SolidColorBrush x:Key="color" Color="Red" />
        </DataGrid.Resources>
        <DataGrid.RowStyle>
            <Style TargetType="DataGridRow">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Statut}" Value="Saisi">
                        <Setter Property="Background" Value="{StaticResource color}" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Statut}" Value="Validé">
                        <Setter Property="Background" Value="{StaticResource color}" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Statut}" Value="Suspendu">
                        <Setter Property="Background" Value="{StaticResource color}" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Statut}" Value="Annulé">
                        <Setter Property="Background" Value="{StaticResource color}" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </DataGrid.RowStyle>
    </DataGrid>
    

    如果您稍微修改一下,您当前的代码隐藏方法将可以正常工作:

        For Each row As DataRowView In dg.Items.OfType(Of DataRowView)
            Dim dgrow As DataGridRow = dg.ItemContainerGenerator.ContainerFromItem(row)
            If Not statutList.Contains(row("Statut").ToString) Then
                dgrow.Background = Brushes.Red
            End If
        Next
    

    请注意,如果 DataTable 包含大量行并且您没有禁用 UI 虚拟化,则 ItemContainerGenerator.ContainerFromItem 方法实际上不会为可能已被虚拟化掉的项目返回 DataGridRow 容器:

    <DataGrid x:Name="dg" VirtualizingPanel.IsVirtualizing="False">.
    

    如果您的 DataTable 包含很多行,显然禁用虚拟化可能会导致性能问题。

    还要注意,一旦真正创建了容器,就需要执行代码,例如当窗口的 Loaded 事件发生时。

    Class MainWindow
        Dim statutList() As String = {"Saisi", "Validé", "Suspendu", "Annulé"}
    
        Public Sub New()
    
            ' This call is required by the designer.
            InitializeComponent()
    
            ' Add any initialization after the InitializeComponent() call.
            Dim dg As New DataGrid
            Dim dataTable As DataTable = ParseFile(filePath)
    
            dg.ItemsSource = dataTable.DefaultView
        End Sub
    
        Private Sub Window_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
            For Each row As DataRowView In dg.Items.OfType(Of DataRowView)
                Dim dgrow As DataGridRow = dg.ItemContainerGenerator.ContainerFromItem(row)
                If Not statutList.Contains(row("Statut").ToString) Then
                    dgrow.Background = Brushes.Red
                End If
            Next
        End Sub
        ...
    End Class
    

    【讨论】:

    • 我很想使用 wpf 方法,但这只是数据检查代码的一小部分。我必须根据其他几个值(+200)检查一些单元格。不幸的是,您的代码隐藏方法代码不起作用。
    • “不起作用”到底是什么意思?您是否遇到异常或发生了什么?一旦真正创建了容器,您就需要执行此代码,例如当窗口的 Loaded 事件发生时。您不能在窗口的构造函数中遍历容器。
    • 我在 dgrow 上收到 NullReferenceException。 DataGrid 实际上是在检查部分之前加载的(For Each 循环位于填充容器的 dg.ItemsSource = dataTable.DefaultView 之后)
    • 不,当您设置 ItemsSource 属性时,不会立即创建可视化容器。您必须等到加载了 DataGrid 或窗口。我已经更新了我的答案以澄清这一点。尝试按照建议处理窗口的 Loaded 事件,它应该可以工作。
    • 你是对的!我实际上是 WPF 的初学者,我不知道必须先加载 DataGrid,然后才能对其进行可视化调整。在 for each 循环之前的 dg.UpdateLayout() 为我做了。我还要感谢你的代码建议,虽然我不能使用它,因为数据网格可以采用不同的csv文件结构,我必须相应地检查数据(这也是我不能这样做的原因XAML,但如果您有任何建议,请告诉我)。
    猜你喜欢
    • 1970-01-01
    • 2016-01-22
    • 1970-01-01
    • 2019-07-26
    • 2012-07-02
    • 2013-09-05
    • 2015-11-26
    • 2019-04-19
    • 1970-01-01
    相关资源
    最近更新 更多