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

Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Envilogger
  • 300
  • 2
  • 8
  • This looks like the expected behaviour to me? Can you clarify what you feel the problem is? – MoonKnight Jul 04 '13 at 16:47
  • 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. – Envilogger Jul 04 '13 at 16:57
  • 2
    What happens if you move the BaseCellClass style to your Application resources (or another location that is loaded before the `Window` is initialized)? – Brian S Jul 04 '13 at 17:32
  • 1
    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 DynamicResource – sa_ddam213 Jul 04 '13 at 23:59
  • Fully agree with the @sa_ddam213. In your case you need to use `Converters`, `DynamicResource` is useless. – Anatoliy Nikolaev Jul 05 '13 at 06:09
  • 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 ways – Envilogger Jul 05 '13 at 07:58

2 Answers2

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.

Richard E
  • 4,819
  • 1
  • 19
  • 25
  • 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: http://stackoverflow.com/questions/9490264/dynamicresource-for-style-basedon – Envilogger Jul 05 '13 at 14:10
  • Anyway I'll mark your answer as right and post my own solution where I use little service for that – Envilogger Jul 05 '13 at 14:11
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

Envilogger
  • 300
  • 2
  • 8