为什么我不能在DataGridColumn.CellStyle中使用DynamicResource?

6
因此,例如我有一个使用简单模型的MVVM WPF应用程序:
public class MyObject
{
    public string F1 { get; set; }
    public string F2 { get; set; }
}

一个简单的视图模型,创建了3行:

public class MyViewModel
{
    public ObservableCollection<MyObject> Objects { get; set; }

    public MyViewModel()
    {
        Objects = new ObservableCollection<MyObject>
            {
                new MyObject{F1 = "V1",F2 = "B1"},
                new MyObject{F1 = "V2",F2 = "B2"},
                new MyObject{F1 = "V3",F2 = "V3"}
            };
    }
}

我有一个 DataGrid,其中包含手动定义的列,并为每个列设置了CellStyle。这两种样式都在Window.Resources块中定义。但是对于第一列,我使用StaticResource,而对于第二列,我使用DynamicResource

XAML视图:

<Window x:Class="WpfApplication12.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525" x:Name="WholeWindow">
<Window.Resources>
    <Style x:Key="BaseCellClass" TargetType="DataGridCell">
        <Setter Property="Foreground" Value="Blue" />
    </Style>
</Window.Resources>
<Grid>
    <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding ElementName=WholeWindow, Path=ViewModel.Objects}">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding F1}" Header="F1" CellStyle="{StaticResource BaseCellClass}" />
            <DataGridTextColumn Binding="{Binding F2}" Header="F2" CellStyle="{DynamicResource BaseCellClass}" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>

所以问题是:在第二列中,资源没有被应用到该列。 查看第二列

这在我看来似乎是预期的行为?你能澄清一下你认为问题是什么吗? - MoonKnight
问题在于CellStyle是一个DependencyProperty,但当我尝试在其中使用绑定时,它无法工作。很明显,他们之所以将其设置为DependencyProperty是有原因的。 - Envilogger
2
如果将BaseCellClass样式移动到应用程序资源中(或加载在“Window”初始化之前的其他位置),会发生什么? - Brian S
1
在DataGrid上使用DynamicResources并不是一个好主意,StaticResource只会被引用元素检索一次,并在整个资源的生命周期内使用。每次使用引用对象时都会获取DynamicResource。如果Datagrid有许多项,则性能损失会相当大,而且如果您在同一文件中声明资源,则无需使用DynamicResource。 - sa_ddam213
完全同意 @sa_ddam213 的观点。在您的情况下,您需要使用 ConvertersDynamicResource 是无用的。 - Anatoliy Nikolaev
是的,StaticResource 当然可以正常工作,但在我的情况下,我需要使用 DynamicResource。这个代码示例只是为了说明问题。在我们的实际应用中,目标是使用 DynamicResource 来实现能够动态更改样式。无论如何,我认为这在 DataGridColumn 的基本实现中是不可能的,因此我正在寻找其他方法。 - Envilogger
2个回答

2
您可以为DataGridCellStyle中的属性创建资源,然后在Style定义中将它们作为DynamicResource引用。根据您的示例,它应该是这样的:
<Window.Resources>
    <SolidColorBrush x:Key="ForegroundBrush" Color="Blue"/>

    <Style x:Key="BaseCellClass" TargetType="DataGridCell">
        <Setter Property="Foreground" Value="{DynamicResource ForegroundBrush}" />
    </Style>
</Window.Resources>
<Grid>
    <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding ElementName=WholeWindow, Path=ViewModel.Objects}">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding F1}" Header="F1" CellStyle="{StaticResource BaseCellClass}" />
            <DataGridTextColumn Binding="{Binding F2}" Header="F2" CellStyle="{StaticResource BaseCellClass}" />
        </DataGrid.Columns>
    </DataGrid>
</Grid>

这些资源当然会放在单独的资源文件中。


谢谢。你的解决方案很好用。但是在问题中我忘了说我需要一种像这个问题中那样派生样式的方法:https://dev59.com/UWkx5IYBdhLWcg3wA_1S - Envilogger
无论如何,我会将您的答案标记为正确,并发布我自己的解决方案,在其中我会使用少量服务。 - Envilogger

1

我找到了一个小服务来解决这个问题。简单来说,我在XAML中编写了以下代码:

<wpfApplication12:DataGridColumnDynamicStyleService TargetGrid="{Binding ElementName=Grid}">
        <wpfApplication12:DataGridColumnDynamicStyleService.ColumnStyles>
            <wpfApplication12:DataGridColumnStyleBinding ColumnTag="C1" DynamicStyle="{DynamicResource BaseCellClass}" />
        </wpfApplication12:DataGridColumnDynamicStyleService.ColumnStyles>
    </wpfApplication12:DataGridColumnDynamicStyleService>
    <DataGrid AutoGenerateColumns="False" ItemsSource="{Binding ElementName=WholeWindow, Path=ViewModel.Objects}" x:Name="Grid">
        <DataGrid.Columns>
            <DataGridTextColumn Binding="{Binding F1}" Header="F1" wpfApplication12:DataGridColumnDynamicStyle.ColumnTag="C1" />
            <DataGridTextColumn Binding="{Binding F2}" Header="F2" wpfApplication12:DataGridColumnDynamicStyle.ColumnTag="C2" />
        </DataGrid.Columns>
    </DataGrid>

在这里,你可以看到我使用了附加属性ColumnTag来标识列。我创建了一个服务控件来定义列的样式,并将目标数据网格设置为TargetGrid。 如果你想查看所有代码,请点击google drive的链接。


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