wpf 如何在 AutoGeneratingColumn 事件期间根据其值设置数据网格单元格的背景?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16645688/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to set background of a datagrid cell during AutoGeneratingColumn event depending on its value?
提问by Ms. Nobody
I'm still fighting with manipulation of cell backgrounds so I'm asking a new question.
我仍在与细胞背景的操作作斗争,所以我在问一个新问题。
A user "H.B." wrote that I can actually set the cell style during the AutoGeneratingColumnevent - Change DataGrid cell colour based on values. The problem is that I'm not sure how to do it.
用户“HB”写道,我实际上可以在AutoGeneratingColumn事件期间设置单元格样式-根据值更改 DataGrid 单元格颜色。问题是我不知道该怎么做。
What I want:Set different background coloursfor each cell depending on its value. If the value is nullI also want it notto be clickable(focusable I guess).
我想要什么:根据每个单元格的值
设置不同的背景颜色。如果值是null我也希望它不可点击(我猜是可聚焦的)。
What I have / I'm trying to do:
我拥有/我正在尝试做的事情:
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;
}
}
}
This is just the pseudocode. Is something like this is possible during column auto-generation and if so, how can I edit my code so it will be valid?
这只是伪代码。在列自动生成过程中是否有可能发生这样的事情,如果是这样,我该如何编辑我的代码以使其有效?
I read about value convertors but I want to know if it's somehow possible programmatically, without writing XAML.
我读过值转换器,但我想知道它是否可以通过编程方式实现,而无需编写 XAML。
Please understand that I'm still a beginner to C#/WPF/DataGrid.
请理解我仍然是 C#/WPF/DataGrid 的初学者。
Solution part1:
解决方案第 1 部分:
I used the answer I accepted. Just put it into
我使用了我接受的答案。把它放进去
<Window.Resources>
<local:ValueColorConverter x:Key="colorConverter"/>
<Style x:Key="DataGridCellStyle1" TargetType="{x:Type DataGridCell}">
<Setter Property="Padding" Value="5"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True">
<Border.Background>
<MultiBinding Converter="{StaticResource colorConverter}">
<Binding RelativeSource="{RelativeSource AncestorType=DataGridCell}" Path="Content.Text"/>
<Binding RelativeSource="{RelativeSource AncestorType=DataGridCell}" Path="IsSelected"/>
</MultiBinding>
</Border.Background>
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
And made for it a MultiBindingconvertor so I can also set the background color for selected cells.
并为它做了一个MultiBinding转换器,所以我还可以为选定的单元格设置背景颜色。
Problem:
问题:
Now I only have to solve the problem of setting focus of empty cells. Any hints?
现在我只需要解决设置空单元格焦点的问题。任何提示?
<Style.Triggers>
<Trigger Property="HasContent" Value="False">
<Setter Property="Focusable" Value="False"/>
</Trigger>
</Style.Triggers>
This doesn't work. I had empty strings in the empty cells, but they are filled with ′null′s so it should work, right? Or what am I doing wrong :| ?
这不起作用。我在空单元格中有空字符串,但它们充满了“null”,所以它应该可以工作,对吧?或者我做错了什么:| ?
Solution part 2:
解决方案第 2 部分:
So the code above won't work as long as the cell value is a ′TextBox′ so I decided to find another way to deal with it which can be found in my answer here: https://stackoverflow.com/a/16673602/2296407
因此,只要单元格值为“TextBox”,上面的代码就不起作用,所以我决定找到另一种方法来处理它,可以在我的答案中找到:https: //stackoverflow.com/a/16673602 /2296407
Thanks for trying to help me :)
感谢您尝试帮助我:)
回答by morincer
I can propose two different solutions for your question: the first is "code-behind-style" (which you are asking for but personally I think it is not right approach in WPF) and more WPF-style (which more tricky but keeps code-behind clean and utilizes styles, triggers and converters)
我可以为您的问题提出两种不同的解决方案:第一个是“代码隐藏风格”(您要求但我个人认为这不是 WPF 中的正确方法)和更多 WPF 风格(更棘手但保留代码-在干净和利用样式、触发器和转换器的背后)
Solution 1. Event handling and code-behind logic for coloring
解决方案 1. 着色的事件处理和代码隐藏逻辑
First of all, the approach you've chosen will not work directly - the AutoGeneratingColumn event is meant to be used for altering the entire columnappearance, not on the cell-by-cell basis. So it can be used for, say, attaching the correct style to entire column basing on it's display index or bound property.
首先,您选择的方法不能直接工作 - AutoGeneratingColumn 事件旨在用于更改整个列的外观,而不是逐个单元格的基础上。因此,它可以用于,例如,根据其显示索引或绑定属性将正确的样式附加到整个列。
Generally speaking, for the first time the event is raised your datagrid will not have any rows (and consequently - cells) at all. If you really need to catch the event - consider your DataGrid.LoadingRow event instead. And you will not be able to get the cells that easy :)
一般来说,第一次引发事件时,您的数据网格根本不会有任何行(因此 - 单元格)。如果您确实需要捕获事件 - 请考虑使用 DataGrid.LoadingRow 事件。而且您将无法轻松获得细胞:)
So, what you do: handle the LoadingRow event, get the row (it has the Itemproperty which holds (surprisingly :)) your bound item), get the bound item, make all needed calculations, get the cell you need to alter and finally alter the style of the target cell.
所以,你要做的是:处理 LoadingRow 事件,获取行(它具有Item属性,它保存(令人惊讶的是:))你的绑定项目),获取绑定项目,进行所有需要的计算,获取你需要更改的单元格和最后改变目标单元格的样式。
Here is the code (as item I use a sample object with the int "Value" property that I use for coloring).
这是代码(作为项目,我使用带有用于着色的 int“Value”属性的示例对象)。
XAML
XAML
<DataGrid Name="mygrid" ItemsSource="{Binding Items}" AutoGenerateColumns="True" LoadingRow="DataGrid_OnLoadingRow"/>
.CS
。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;
}
Solution 2. WPF-style
解决方案2.WPF风格
This solution uses code-behind only for value-to-color convertions (assuming that that logic of coloring is more complex than equality comparison - in that case you can use triggers and do not mess with converters).
此解决方案仅将代码隐藏用于值到颜色的转换(假设着色逻辑比相等比较更复杂 - 在这种情况下,您可以使用触发器并且不要弄乱转换器)。
What you do: set DataGrid.CellStyle property with style that contains a data trigger, which checks if the cell is within a desired column (basing on it's DisplayIndex) and if it is - applies background through a converter.
你做什么:用包含数据触发器的样式设置 DataGrid.CellStyle 属性,它检查单元格是否在所需的列内(基于它的 DisplayIndex),如果是 - 通过转换器应用背景。
XAML
XAML
<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
。CS
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();
}
}
UPD:If you need to color entire datagrid, XAML is much easier (no need to use triggers). Use the following CellStyle:
UPD:如果您需要为整个数据网格着色,XAML 更容易(无需使用触发器)。使用以下 CellStyle:
<DataGrid.CellStyle>
<Style TargetType="DataGridCell">
<Setter Property="Background" Value="{Binding RelativeSource={RelativeSource Self}, Path=Content.Text, Converter={StaticResource colorconverter}}"/>
</Style>
</DataGrid.CellStyle>
回答by H.B.
What i meant is that you can set the CellStyleproperty of the column, you can not manipulate cells directly as they are not available in this event. The style can contain your conditional logic in the form of DataTriggers(will need a converter as you have "less-than" and not equals) and Setters.
我的意思是你可以设置CellStyle列的属性,你不能直接操作单元格,因为它们在这个事件中不可用。该样式可以包含以下形式的条件逻辑DataTriggers(将需要一个转换器,因为您有“小于”和不等于)和Setters.
Also if the logic is not specific to the columns you can set the style globally on the griditself. The point of using the event would be to manipulate the column properties which you can not access otherwise.
回答by KbManu
I am not sure whether this property (Cell.Style) is available in your WPF Datagrid. Probably some alternative exists in your case. It has worked for WinForms datagrid.
我不确定此属性 (Cell.Style) 在您的 WPF Datagrid 中是否可用。您的情况可能存在一些替代方案。它适用于 WinForms 数据网格。
cell.Style.BackColor = System.Drawing.Color.Black;

