C# 如何在自动生成列事件期间根据其值设置datagrid单元格的背景?

C# 如何在自动生成列事件期间根据其值设置datagrid单元格的背景?,c#,wpf,datagrid,background,autogeneratecolumn,C#,Wpf,Datagrid,Background,Autogeneratecolumn,我仍在与细胞背景的操纵作斗争,所以我要问一个新问题 一位用户“H.B.”写道,我实际上可以在事件期间设置单元格样式-。问题是我不知道怎么做 我想要什么: 根据每个单元格的值设置不同的背景色。如果该值为null,我也希望它不是可点击的(我猜是可聚焦的) 我所拥有的/我正在努力做的: private void mydatagrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e) { fo

我仍在与细胞背景的操纵作斗争,所以我要问一个新问题

一位用户“H.B.”写道,我实际上可以在事件期间设置单元格样式-。问题是我不知道怎么做

我想要什么: 根据每个单元格的值设置不同的背景色。如果该值为
null
,我也希望它不是可点击的(我猜是可聚焦的)

我所拥有的/我正在努力做的:

private void mydatagrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    foreach (Cell cell in e.Column)
    {
        if (cell.Value < 1)
        { 
            cell.Background = Color.Black; 
            cell.isFocusable = false; 
        } 
        else
        {
            cell.Background = Color.Pink;
        }
    }
}
这不管用。我在空单元格中有空字符串,但它们都是空的,所以应该可以工作,对吗?或者我做错了什么:|

解决方案第2部分: 因此,只要单元格值是“文本框”,上面的代码就不起作用,因此我决定找到另一种处理方法,可以在我的答案中找到:


感谢您尝试帮助我:)

我不确定此属性(Cell.Style)是否在您的WPF数据网格中可用。在你的情况下可能存在一些替代方案。它已经为WinForms datagrid工作

 cell.Style.BackColor = System.Drawing.Color.Black;

我的意思是,您可以设置列的属性,您不能直接操作单元格,因为它们在本事件中不可用。样式可以包含
DataTriggers
形式的条件逻辑(需要一个转换器,因为您有“小于”和“不等于”)和
Setters


此外,如果逻辑不是特定于列,则可以设置逻辑本身。使用此事件的目的是操作您无法访问的列属性。

我可以为您的问题提出两种不同的解决方案:第一种是“代码隐藏样式”(您要求使用此样式,但我个人认为它在WPF中不正确),另一种是WPF样式(这更复杂,但保持代码干净,并利用样式、触发器和转换器)

解决方案1.事件处理和着色代码隐藏逻辑 首先,您选择的方法不会直接起作用-AutoGeneratingColumn事件用于更改整个列的外观,而不是逐个单元格。因此,它可以用于(例如)根据显示索引或绑定属性将正确的样式附加到整个列

一般来说,第一次发生事件时,DATAGRID将没有任何行(因此是单元格)。如果你真的需要捕获这个事件,那么就考虑你的DATAGIDID.LoopIn Reo事件,而你将无法得到简单的单元:

因此,您要做的是:处理LoadingRow事件,获取行(它具有保存绑定项的Item属性(令人惊讶:)),获取绑定项,进行所有需要的计算,获取需要更改的单元格,最后更改目标单元格的样式

下面是代码(作为项,我使用了一个带有int“Value”属性的示例对象,该属性用于着色)

XAML

   <DataGrid Name="mygrid" ItemsSource="{Binding Items}" AutoGenerateColumns="True" LoadingRow="DataGrid_OnLoadingRow"/>
<DataGrid Name="mygrid" ItemsSource="{Binding Items}" AutoGenerateColumns="True">
        <DataGrid.Resources>
            <local:ValueColorConverter x:Key="colorconverter"/>
        </DataGrid.Resources>
        <DataGrid.CellStyle>
            <Style TargetType="DataGridCell">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Column.DisplayIndex}" Value="1">
                        <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.Text, Converter={StaticResource colorconverter}}"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </DataGrid.CellStyle>
    </DataGrid>

.CS

    private void DataGrid_OnLoadingRow(object sender, DataGridRowEventArgs e)
    {
        Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() => AlterRow(e)));
    }

    private void AlterRow(DataGridRowEventArgs e)
    {
        var cell = GetCell(mygrid, e.Row, 1);
        if (cell == null) return;

        var item = e.Row.Item as SampleObject;
        if (item == null) return;

        var value = item.Value;

        if (value <= 1) cell.Background = Brushes.Red;
        else if (value <= 2) cell.Background = Brushes.Yellow;
        else cell.Background = Brushes.Green;
    }

    public static DataGridRow GetRow(DataGrid grid, int index)
    {
        var row = grid.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow;

        if (row == null)
        {
            // may be virtualized, bring into view and try again
            grid.ScrollIntoView(grid.Items[index]);
            row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
        }
        return row;
    }

    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++)
        {
            var v = (Visual)VisualTreeHelper.GetChild(parent, i);
            child = v as T ?? GetVisualChild<T>(v);
            if (child != null)
            {
                break;
            }
        }
        return child;
    }

    public static DataGridCell GetCell(DataGrid host, DataGridRow row, int columnIndex)
    {
        if (row == null) return null;

        var presenter = GetVisualChild<DataGridCellsPresenter>(row);
        if (presenter == null) return null;

        // try to get the cell but it may possibly be virtualized
        var cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);
        if (cell == null)
        {
            // now try to bring into view and retreive the cell
            host.ScrollIntoView(row, host.Columns[columnIndex]);
            cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);
        }
        return cell;

    }
private void DataGrid\u OnLoadingRow(对象发送方,DataGridRowEventArgs e)
{
Dispatcher.BeginInvoke(DispatcherPriority.Render,新操作(()=>AlterRow(e));
}
私有void AlterRow(DataGridRowEventArgs e)
{
var cell=GetCell(mygrid,即第1行);
if(cell==null)返回;
var item=e.Row.item作为SampleObject;
如果(item==null)返回;
var值=项目价值;

if(您可以在grid.Auto-generated单元格的rowdabund事件中尝试此值,当然,它有“content”-它是(这就是为什么我在回答中使用content.Text):)尝试使用@Moriancer谢谢你的帮助。我以另一种方式处理空单元格,因为DataTrigger不想与我一起工作,我已经非常生气了:D。但真的谢谢你的支持。@好朋友,没问题。在你的答案中添加了一些代码样式的注释,尽管它更像是假代码=伪代码:)(虽然我也有同样的问题,但我正在寻找CodeBehind中的解决方案您应该实现一个“小于转换器”或者类似,因为
IsFocusable
也应该更改。感谢这个非常长且有用的答案。转换器工作良好,我认为,但这些单元格不想着色。我尝试编辑设置,而且我正在使用双值。-编辑了一点。但仍然。我对数据绑定不够友好。是否你认为可能有问题吗?我正在用datatable从dataset的c代码中填充datagrid。我在convertor中获得了正确的值,但它不会给我的单元格背景上色:'(请发布一段用于绑定网格和着色的代码(XAML+代码隐藏)所以我可以检查出哪里出了问题?好吧,如果有什么愚蠢的事情,请不要笑。但问题是,我在datagrid中需要的东西并不总是相同的数量(行/列的数量)因此,我用这些东西填充一个数据表,并将该表放入dataset,只是因为它以某种方式工作。我总是使用以下代码通过单击按钮来填充datagrid数据:
mydatagrid.ItemsSource=dataset.Tables[0].DefaultView;
它可以工作,但我不确定如何将这种填充网格与背景色的设置连接起来。我没有在xaml中编写任何关于绑定的内容,只要这样做就可以了。我使用的是u发布的代码。只是将int替换为double everywhere,因为我的值是double。我真的不明白c应该如何使用XAML中的ode工作。我得到了触发器,但我不明白绑定是如何工作的。中的那个。你能帮我理解一下吗?
    private void DataGrid_OnLoadingRow(object sender, DataGridRowEventArgs e)
    {
        Dispatcher.BeginInvoke(DispatcherPriority.Render, new Action(() => AlterRow(e)));
    }

    private void AlterRow(DataGridRowEventArgs e)
    {
        var cell = GetCell(mygrid, e.Row, 1);
        if (cell == null) return;

        var item = e.Row.Item as SampleObject;
        if (item == null) return;

        var value = item.Value;

        if (value <= 1) cell.Background = Brushes.Red;
        else if (value <= 2) cell.Background = Brushes.Yellow;
        else cell.Background = Brushes.Green;
    }

    public static DataGridRow GetRow(DataGrid grid, int index)
    {
        var row = grid.ItemContainerGenerator.ContainerFromIndex(index) as DataGridRow;

        if (row == null)
        {
            // may be virtualized, bring into view and try again
            grid.ScrollIntoView(grid.Items[index]);
            row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromIndex(index);
        }
        return row;
    }

    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++)
        {
            var v = (Visual)VisualTreeHelper.GetChild(parent, i);
            child = v as T ?? GetVisualChild<T>(v);
            if (child != null)
            {
                break;
            }
        }
        return child;
    }

    public static DataGridCell GetCell(DataGrid host, DataGridRow row, int columnIndex)
    {
        if (row == null) return null;

        var presenter = GetVisualChild<DataGridCellsPresenter>(row);
        if (presenter == null) return null;

        // try to get the cell but it may possibly be virtualized
        var cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);
        if (cell == null)
        {
            // now try to bring into view and retreive the cell
            host.ScrollIntoView(row, host.Columns[columnIndex]);
            cell = (DataGridCell)presenter.ItemContainerGenerator.ContainerFromIndex(columnIndex);
        }
        return cell;

    }
<DataGrid Name="mygrid" ItemsSource="{Binding Items}" AutoGenerateColumns="True">
        <DataGrid.Resources>
            <local:ValueColorConverter x:Key="colorconverter"/>
        </DataGrid.Resources>
        <DataGrid.CellStyle>
            <Style TargetType="DataGridCell">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding RelativeSource={RelativeSource Self}, Path=Column.DisplayIndex}" Value="1">
                        <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.Text, Converter={StaticResource colorconverter}}"/>
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </DataGrid.CellStyle>
    </DataGrid>
public class ValueColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var str = value as string;
        if (str == null) return null;

        int intValue;
        if (!int.TryParse(str, out intValue)) return null;

        if (intValue <= 1) return Brushes.Red;
        else if (intValue <= 2) return Brushes.Yellow;
        else return Brushes.Green;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
    <DataGrid.CellStyle>
            <Style TargetType="DataGridCell">
                 <Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.Text, Converter={StaticResource colorconverter}}"/>
            </Style>
    </DataGrid.CellStyle>