使用foreach循环遍历WPF DataGrid

6

大家好,我正在尝试使用for each循环遍历WPF的DataGrid,以更改错误单元格的背景颜色。我查看了许多相关问题,但仍未找到满意的答案。目前我已经有以下代码:

public void RunChecks()
{
    const int baseColumnCount = 3;
    foreach (DataRowView rv in dataGrid.Items)
    {
        for (int i = baseColumnCount; i < dataGrid.Columns.Count; i++)
        {
            if (!CheckForBalancedParentheses(rv.Row[i].ToString()))
            {
                Color color = (Color)ColorConverter.ConvertFromString("#FF0000");
                row.Background = new SolidColorBrush(color); // Problem!
            }
        }
    }
}

问题在于,为了更改DataGrid中一行的 Background 颜色,我需要使用与 DataRowView rv相关联的 DataGridRow 对象。 如何从对象rv (DataRowView)获取对DataGridRow的引用? 感谢您的时间。 编辑:根据下面的建议,我现在有了以下工作鼠标悬停事件并设置相关单元格的背景和前景字体的样式。然而,我真的不知道如何在我的上述代码中运行时将背景颜色应用于单元格。XML样式是:
<Window.Resources>
    <Style TargetType="{x:Type DataGridRow}">
        <Style.Triggers>
            <Trigger Property="IsMouseOver"
                     Value="True">
                <Setter Property="Background" Value="Red" />
                <Setter Property="FontWeight" Value="ExtraBold" />
            </Trigger>
        </Style.Triggers>
    </Style>
</Window.Resources>
5个回答

5
当您使用WPF时,避免直接访问UI构件。 在您的ModelView中创建一个属性Color,并将其绑定到DataGrid视图的单行模板的背景颜色上。
因此,为了更改颜色,您需要循环遍历ModelView集合,并设置/读取每个对象绑定到每个单独行的Color属性。通过更改它,如果绑定正确设置,您将影响行UI颜色外观。
有关具体示例,您可以查看: 如何将数据网格行的背景绑定到特定颜色?

1
感谢您的时间。我会采纳您的建议并开始阅读。我还一直在尝试着着色整个列,但无济于事。如果您有兴趣并想获取声望值,我已在此处提出了另一个问题。再次感谢... - MoonKnight
1
@Killercam:对于行和列,思路是一样的。如果UI对象提供了某个属性(在这种情况下是颜色),可以通过直接访问或绑定来进行更改,那么你应该使用模型视图对象中的绑定。 - Tigran
1
谢谢。我已经读了一本有关样式、触发器等方面的章节,现在能够在鼠标悬停事件上更改行的颜色。但是,我不知道如何使用这些样式在运行时从代码中更改单元格/行的所需颜色。如果您能在这方面提供任何帮助,将不胜感激... 我已经编辑了问题以显示我所拥有的样式。 - MoonKnight
1
@Killercam:看这里:http://stackoverflow.com/questions/5030361/how-do-i-programatically-change-datagrid-row-color-in-wpf,希望能帮到你。不幸的是,这不是可以在问答网站上简单回答的问题。需要定义DataModel、ModelView,在ModelView中定义颜色属性,并在XAML中进行绑定,在运行时访问ModelView对象及其属性以影响UI。 - Tigran

2
您可以使用ItemContainerGenerator来获取数据的可视化表示,即DataGridRow -
DataGridRow row = (DataGridRow)dataGrid.ItemContainerGenerator
                                       .ContainerFromItem(rv);

1
这里返回了 nullrow。我已经检查了 rv,它是非空的。很抱歉再次打扰您,感谢您的时间... - MoonKnight
1
只有在行尚未在您的 GUI 上呈現時,它才會返回 null。您正在處理多少行,並且您的表格啟用了 虛擬化 - Rohit Vats
1
这个链接可能会对你有所帮助:https://dev59.com/pmw15IYBdhLWcg3wSJvQ。 - Rohit Vats
1
目前仅有1行至1000行,总的来说数量并不算多。我对DataGrid的可视化属性Visulisation不太熟悉。我已尝试用XML编写,但未发现具有此名称的属性... 再次感谢。 - MoonKnight
1
尝试在数据网格上设置 VirtualizingStackPanel.IsVirtualizing="False",如上面提供的链接中所述。但是,这会有一个权衡,即所有1000行将一次性呈现。 - Rohit Vats
1
现在我在foreach循环的初始化中得到了“无法将类型为'MS.Internal.NamedObject'的对象强制转换为类型'System.Data.DataRowView'。”的错误。 - MoonKnight

1
"Killercam"的答案对我有用,但我需要添加以下内容:

myDataGrid.UpdateLayout();

在使用GetCell方法之前,我确信我不会得到空引用。

要获取整个Helper类,请查看DataGridHelper

经过那么多的痛苦,我尝试运行整个代码,但我遇到了另一个问题,正确着色的单元格在滚动时发生了变化,解决方案是启用虚拟化并将其模式设置为标准。

VirtualizingStackPanel.IsVirtualizing="True"
VirtualizingStackPanel.VirtualizationMode="Standard"

希望这可以帮助需要迭代数据表单单元格的任何人。


0
//the Class that resembles the Datagrid Item schema

foreach (Class cl in dgDatagrid.Items)
   {
       MessageBox.Show(cl.ID.ToString());
   }

this is the most simplest way to read the datagrid data
most articles misguide such simple things

0

经过大量阅读,我找到了一种方法来实现我想要的功能 - 根据特定条件在运行时着色单元格。这是我用来进行着色的方法

public void RunChecks()
{
    const int baseColumnCount = 3;
    for (int i = baseColumnCount; i < dataGrid.Columns.Count; i++)
    {
        foreach (DataGridRow row in Utilities.GetDataGridRows(dataGrid))
        {
            if (row != null)
            {
                DataGridCell cell = dataGrid.GetCell(row, i);

                // Start work with cell.
                Color color;
                TextBlock tb = cell.Content as TextBlock;
                string cellValue = tb.Text;
                if (!CheckForBalancedParentheses(cellValue))
                    color = (Color)ColorConverter.ConvertFromString("#FF0000");
                else
                    color = (Color)ColorConverter.ConvertFromString("#FFFFFF");
                row.Background = new SolidColorBrush(color);
                //cell.Background = new SolidColorBrush(color);
            }
        }
    }
}

这些是所需的相关实用方法

public static T GetVisualChild<T>(Visual parent) where T : Visual
{
    T child = default(T);
    int numVisuals = VisualTreeHelper.GetChildrenCount(parent);
    for (int i = 0; i < numVisuals; i++)
    {
        Visual v = (Visual)VisualTreeHelper.GetChild(parent, i);
        child = v as T;
        if (child == null)
            child = GetVisualChild<T>(v);
        if (child != null)
            break;
    }
    return child;
}

public static DataGridCell GetCell(this DataGrid grid, DataGridRow row, int column)
{
    if (row != null)
    {
        DataGridCellsPresenter presenter = GetVisualChild<DataGridCellsPresenter>(row);
        if (presenter == null)
        {
            grid.ScrollIntoView(row, grid.Columns[column]);
            presenter = GetVisualChild<DataGridCellsPresenter>(row);
        }
        DataGridCell cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(column);
        return cell;
    }
    return null;
}

public static IEnumerable<DataGridRow> GetDataGridRows(DataGrid grid)
{
    var itemsSource = grid.ItemsSource as IEnumerable;
    if (null == itemsSource) yield return null;
    foreach (var item in itemsSource)
    {
        var row = grid.ItemContainerGenerator.ContainerFromItem(item) as DataGridRow;
        if (null != row) yield return row;
    }
}

请注意,当用户滚动时,单元格的颜色会从一个单元格移动到另一个单元格!? 这是 WPF 的又一个惊人的烦恼。 我真的很困惑为什么这么简单的事情会变得如此困难。 我认为需要使用 MVVM 类型模式来处理这种情况的建议非常惊人...

我希望这可以帮助其他人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接