Why can't I use DynamicResource with DataGridColumn.CellStyle
Asked Answered
R

2

6

So, for example I have some MVVM WPF application with simple model:

public class MyObject
{
    public string F1 { get; set; }
    public string F2 { get; set; }
}

and simple view model that creates 3 rows:

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"}
            };
    }
}

And in view I have a DataGrid with manually defined columns and for each column I set CellStyle. Both styles defined in Window.Resources block. But for first column, I use StaticResource and for the second DynamicResource

View 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>

So the problem is: in the second column, the resource doesn't get applied to the column.

see second column

Rules answered 4/7, 2013 at 16:44 Comment(6)
This looks like the expected behaviour to me? Can you clarify what you feel the problem is?Strata
The problem is that CellStyle is a DependencyProperty, but when I try to use binding in it, it fails to work. Clearly they've made it DependencyProperty for a reason.Rules
What happens if you move the BaseCellClass style to your Application resources (or another location that is loaded before the Window is initialized)?Frowzy
Using DynamicResources on a DataGrid is not a great idea, StaticResource are retrieved only once by the referencing element and used for entire life of the resource. DynamicResource are acquired every time the referenced object is used. The performance hit on a Datagrid with many Items would be quite big, also if you are declaring the Resource in the same file there is no need to use DynamicResourceMettlesome
Fully agree with the @sa_ddam213. In your case you need to use Converters, DynamicResource is useless.Chromogen
Yeah, StaticResource will work fine ofc, but in my case I need to use DynamicResource. This code sample I made just to illustrate the problem. In our real application the goal is to use DynamicResource to be able to change styles on the fly. Anyway I think this is impossible with basic realization of DataGridColumn and I looking for other waysRules
D
2

You could create resources for the properties in your DataGridCell Style and then reference them as a DynamicResource within the Style definition:

Based on your example it would look like this:

<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>

The resources would of course be located in separate resource files.

Danelle answered 5/7, 2013 at 9:33 Comment(2)
Thank you. Your soulution works fine. But in the question I forgot to say that I need a way to derive styles like in this question: #9490764Rules
Anyway I'll mark your answer as right and post my own solution where I use little service for thatRules
R
1

I found solution with using a little service. In few words I write in xaml this code:

<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>

Here, as you can see, I use attached property ColumnTag to identify columns. And I create a service control that defines styles for columns and set target datagrid as TargetGrid If you want to see all the code, here is the link to the solution on google drive

Rules answered 5/7, 2013 at 14:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.