wpf 为什么我不能设置 DataGridTextColumn 的样式?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2630292/
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
Why can't I style a DataGridTextColumn?
提问by Nike
I tried to create a Style for DataGridTextColumn
with the following code
我尝试DataGridTextColumn
使用以下代码创建样式
<Style TargetType="{x:Type DataGridTextColumn}">
...
</Style>
However, Visual Studio 2010 highlights {x:Type DataGridTextColumn}
with a blue line and elaborates: Exception has been thrown by the target of an invocation.
但是,Visual Studio 2010{x:Type DataGridTextColumn}
以蓝线突出显示并详细说明:Exception has been thrown by the target of an invocation.
Why does this happen and how do I fix it?
为什么会发生这种情况,我该如何解决?
采纳答案by Ray Burns
You can't style the DataGridTextColumn
because DataGridTextColumn
does not derive from FrameworkElement
(or FrameworkContentElement
). Only FrameworkElement, etc supports styling.
你不能设置样式DataGridTextColumn
因为DataGridTextColumn
不是从FrameworkElement
(或FrameworkContentElement
)派生的。只有 FrameworkElement 等支持样式。
When you attempt to create a style in XAML for any type that is not a FrameworkElement
or FrameworkContentElement
you get that error message.
当您尝试用XAML创建一个样式的任何类型的不是一个FrameworkElement
或FrameworkContentElement
你会得到错误信息。
How do you solve this? As with any problem, where there is a will there is a way. In this case I think the easiest solution is to create an attached property for DataGrid to assign a DataGridColumn style:
你如何解决这个问题?与任何问题一样,有志者事竟成。在这种情况下,我认为最简单的解决方案是为 DataGrid 创建附加属性以分配 DataGridColumn 样式:
<DataGrid ...>
<local:MyDataGridHelper.TextColumnStyle>
<Style TargetType="FrameworkElement">
... setters here ...
</Style>
</local:MyDataGridHelper.TextColumnStyle>
...
The implementation would be something along these lines:
实现将是这样的:
public class MyDataGridHelper : DependencyObject
{
// Use propa snipped to create attached TextColumnStyle with metadata:
... RegisterAttached("TextColumnStyle", typeof(Style), typeof(MyDataGridHelper), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
var grid = (DataGrid)obj;
if(e.OldValue==null && e.NewValue!=null)
grid.Columns.CollectionChanged += (obj2, e2) =>
{
UpdateColumnStyles(grid);
}
}
}
private void UpdateStyles(DataGrid grid)
{
var style = GetTextColumnStyle(grid);
foreach(var column in grid.Columns.OfType<DataGridTextColumn>())
foreach(var setter in style.Setters.OfType<Setter>())
if(setter.Value is BindingBase)
BindingOperations.SetBinding(column, setter.Property, setter.Value);
else
column.SetValue(setter.Property, setter.Value);
}
}
The way this works is, any time the attached property is changed, a handler is added for the Columns.CollectionChanged event on the grid. When the CollectionChanged event fires, all columns are updated with the style that was set.
其工作方式是,每当更改附加属性时,都会为网格上的 Columns.CollectionChanged 事件添加处理程序。当 CollectionChanged 事件触发时,所有列都将更新为设置的样式。
Note that the above code does not handle the situation where a style is removed and re-added gracefully: Two event handlers are registered. For a really robust solution you would want to fix this by adding another attached property containing the event handler so the event handler could be unregistered, but for your purpose I think this is unimportant.
请注意,上面的代码没有处理样式被删除并优雅地重新添加的情况:注册了两个事件处理程序。对于真正强大的解决方案,您可能希望通过添加另一个包含事件处理程序的附加属性来解决此问题,以便可以取消注册事件处理程序,但就您的目的而言,我认为这并不重要。
Another caveat here is that the direct use of SetBinding and SetValue will cause the DependencyProperty to have a BaseValueSource of Local
instead of DefaultStyle
. This will probably make no difference in your case but I thought I should mention it.
这里的另一个警告是,直接使用 SetBinding 和 SetValue 将导致 DependencyProperty 的 BaseValueSourceLocal
不是DefaultStyle
。这可能对你的情况没有影响,但我想我应该提到它。
回答by Patrick Graham
The style tag has to go in the right place. Your datagrid may look something like this right now:
样式标签必须放在正确的位置。您的数据网格现在可能看起来像这样:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn />
</DataGrid.Columns>
</DataGrid>
You might initially try to add the style tag directly within the DataGridTextColumn element which will not work. You can however create elements for "DataGridTextColumn.ElementStyle" and or "DataGridTextColumn.EditingElementStyle" just within the "DataGridTextColumn" element. Each of those element tags can then have style tags within them:
您最初可能会尝试直接在 DataGridTextColumn 元素中添加样式标记,但这是行不通的。但是,您可以仅在“DataGridTextColumn”元素中为“DataGridTextColumn.ElementStyle”和/或“DataGridTextColumn.EditingElementStyle”创建元素。这些元素标签中的每一个都可以在其中包含样式标签:
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn>
<DataGridTextColumn.ElementStyle>
<Style TargetType="TextBlock">
<Setter Property="Background" Value="Green"></Setter>
</Style>
</DataGridTextColumn.ElementStyle>
<DataGridTextColumn.EditingElementStyle>
<Style TargetType="TextBox">
<Setter Property="Background" Value="Orange"></Setter>
</Style>
</DataGridTextColumn.EditingElementStyle>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
One style will be applied to viewing and the other will be applied when the cell is in edit mode. Note that it changes from a TextBlock when viewing to a TextBox when editing (This got me at first!).
一种样式将应用于查看,而另一种样式将在单元格处于编辑模式时应用。请注意,它从查看时的 TextBlock 更改为编辑时的 TextBox(这让我一开始!)。
回答by pedrito
This is more an addition to Ray Burns answer. I first wasn't able to implement it on my own, but with help of mm8 (https://stackoverflow.com/a/46690951/5381620) I got it running. Works really fine. For other people who have problems following this attached property approach maybe a full code snippet is helpful.
这更多是对 Ray Burns 回答的补充。我首先无法自己实现它,但是在 mm8 ( https://stackoverflow.com/a/46690951/5381620) 的帮助下,我让它运行了。工作得很好。对于遵循此附加属性方法有问题的其他人,完整的代码片段可能会有所帮助。
public class MyDataGridHelper : DependencyObject
{
private static readonly DependencyProperty TextColumnStyleProperty = DependencyProperty.RegisterAttached("TextColumnStyle", typeof(Style), typeof(MyDataGridHelper), new PropertyMetadata
{
PropertyChangedCallback = (obj, e) =>
{
var grid = (DataGrid)obj;
if (e.OldValue == null && e.NewValue != null)
grid.Columns.CollectionChanged += (obj2, e2) =>
{
UpdateColumnStyles(grid);
};
}
});
public static void SetTextColumnStyle(DependencyObject element, Style value)
{
element.SetValue(TextColumnStyleProperty, value);
}
public static Style GetTextColumnStyle(DependencyObject element)
{
return (Style)element.GetValue(TextColumnStyleProperty);
}
private static void UpdateColumnStyles(DataGrid grid)
{
var origStyle = GetTextColumnStyle(grid);
foreach (var column in grid.Columns.OfType<DataGridTextColumn>())
{
//may not add setters to a style which is already in use
//therefore we need to create a new style merging
//original style with setters from attached property
var newStyle = new Style();
newStyle.BasedOn = column.ElementStyle;
newStyle.TargetType = origStyle.TargetType;
foreach (var setter in origStyle.Setters.OfType<Setter>())
{
newStyle.Setters.Add(setter);
}
column.ElementStyle = newStyle;
}
}
}
xaml
xml
<Grid>
<DataGrid Name="MyDataGrid" ItemsSource="{Binding Lines}" AutoGenerateColumns="False" >
<local:MyDataGridHelper.TextColumnStyle>
<Style TargetType="TextBlock">
<Setter Property="TextWrapping" Value="Wrap"/>
</Style>
</local:MyDataGridHelper.TextColumnStyle>
<DataGrid.Columns>
<DataGridTextColumn Header="ProductId1" Binding="{Binding Path=Result1}" />
<DataGridTextColumn Header="ProductId2" Binding="{Binding Path=Result2}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
Edit: In first approach I did overwrite the whole style. In new version it is still possible to maintain other styles modifications like this one
编辑:在第一种方法中,我确实覆盖了整个样式。在新版本中仍然可以保持像这样的其他样式修改
<DataGridTextColumn.ElementStyle>
<Style TargetType="{x:Type TextBlock}">
<Setter Property="Foreground" Value="Red"/>
</Style>
</DataGridTextColumn.ElementStyle>
回答by david
More simple:
更简单:
<FontFamily x:Key="DefaultFont">Snap ITC</FontFamily>
<Style x:Key="ControlStyle" TargetType="Control">
<Setter Property="FontFamily" Value="{StaticResource DefaultFont}"/>
</Style>
<Style TargetType="{x:Type DataGridCellsPresenter}" BasedOn="{StaticResource ControlStyle}">
</Style>
回答by Tulika Verma
A DataGridTextColumn is nothing but a column with a TextBlock in it. Write a style with the TargetType as TextBlock and bind the ElementStyle property of the DataGridTextColumn to it. Hope that helps!
DataGridTextColumn 只不过是一个带有 TextBlock 的列。编写一个 TargetType 作为 TextBlock 的样式,并将 DataGridTextColumn 的 ElementStyle 属性绑定到它。希望有帮助!