wpf
wpf copied to clipboard
DynamicResource is not working for Header property in DataGridTextColumn
- .NET Core Version: .Net 6.0
- Does the bug reproduce also in WPF for .NET Framework 4.8?: Yes
Problem description:
I have defined the DynamicResource for Header property in DataGridTextColumn of DataGrid. Please refer the below code snippet,
<Application.Resources>
<System:String x:Key="firstName" >Before Change Name</System:String>
<System:String x:Key="secondName" >After Change Name</System:String>
</Application.Resources>
<DataGridTextColumn Binding="{Binding CustomerID}"
Header="{DynamicResource firstName}" />
When change the resource at runtime Header property does not change the value in DataGrid. Can you please check and elaborate why DynamicResource is not working in DataGridTextColumn.Header property of DataGrid?
Note : If we use HeaderTemplate property in DataGridTextColumn its working properly in DataGrid. Please refer the code snippet,
<Window.Resources>
<DataTemplate x:Key="headerTemplate">
<TextBlock Height="50"
Text="{DynamicResource firstName}"
TextWrapping="Wrap" />
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="200" />
</Grid.ColumnDefinitions>
<DataGrid x:Name="dataGrid"
ItemsSource="{Binding Orders}"
AutoGenerateColumns="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding OrderID}"
HeaderTemplate="{StaticResource headerTemplate}" />
<DataGridTextColumn Binding="{Binding CustomerID}"
Header="{DynamicResource firstName}" />
<DataGridTextColumn Binding="{Binding CustomerName}" Header="Customer Name" />
<DataGridTextColumn Binding="{Binding Country}" Header="Country" />
<DataGridTextColumn Binding="{Binding UnitPrice}" Header="Unit Price" />
</DataGrid.Columns>
</DataGrid>
</Grid>
Please refer the Screenshot for your reference

Minimal repro: Step 1: Run the sample
Step 2: Click the Change resource button
Actual behavior: DynamicResource is not working for Header property in DataGridTextColumn
Expected behavior: DynamicResource is working properly for Header property in DataGridTextColumn
I have attached the sample for your reference. Sample Link: DataGrid.zip
Can you please check and provide the solution to use the DynamicResource in Header property in DataGridTextColumn?
Regards, Vijayarasan S
The DataGridColumns are only descriptors, based on which the actual elements are created. The column headers are presented by DataGridColumnHeadersPresenter, an ItemsControl using DataGridColumnHeader as a container. When DataGridColumnHeader container is created, the property values are transferred onto it from DataGridColumn, e.g. the DataGridColumn.Header property onto DataGridColumnHeader.Content property (similar with templates):
https://github.com/dotnet/wpf/blob/b63c69eaf5b58e758765a37bb18064bbc94832ad/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/Controls/Primitives/DataGridRowHeader.cs#L326-L331
Notably, it's property values, not the DP expressions that are copied over.
Now the DynamicResource resp. ResourceReferenceExpression needs something that can provide the resources. It looks for an inheritance context of the target DependencyObject. However, DataGridColumn not only is not in the visual tree as discussed above, it inherits directly from DependencyObject and does not implement any inheritance context.
There is a special provision in the ResourceReferenceExpression for the cases where the target object does not have any inheritance context, which fallbacks to app and/or system resources. In the example above, this is where the initial value comes from:
https://github.com/dotnet/wpf/blob/89d172db0b7a192de720c6cfba5e28a1e7d46123/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ResourceReferenceExpression.cs#L150-L151
Finally, when resource is changed, the owner of the ResourceDictionary is notified. For Framework[Content]Element owners, the ResourcesChanged event is raised. For app resources, the event is propagated through the tree in app's windows:
https://github.com/dotnet/wpf/blob/89d172db0b7a192de720c6cfba5e28a1e7d46123/src/Microsoft.DotNet.Wpf/src/PresentationFramework/System/Windows/ResourceDictionary.cs#L1690
If ResourcesReferenceExpression can get hold of inheritance context in the form of Framework[Content]Element, it can simply subscribe to the ResourcesChanged event and propagate the changes to the target DO. Any changes to the app resources will come to it through the visual tree.
As we noted above, in this scenario we have neither inheritance context nor visual tree. The app/system resources have no other means of notifying of changes, so the ResourceReferenceExpression does not have any way to subscribe to the changes in this case.
I believe that an easy way to hotfix this issue would be to for the DataGridColumn to return DataGridOwner as its InheritanceContext. (That sounds like a reasonable idea anyway, unless I missed some undesirable consequences.)
However, that would not fix the issue for other types in this situation (including user types). It seems that Application and perhaps even SystemResources should have an event that the ResourceReferenceExpression could subscribe to to learn about changes to these resources.
@vijayarasan
For this one you are mixing two things together, you have to pick either of the ones mentioned below.
Either use
<Window.Resources>
<DataTemplate x:Key="headerTemplate">
<TextBlock Height="50"
Text="{DynamicResource firstName}"
TextWrapping="Wrap" />
</DataTemplate>
</Window.Resources>
and
<DataGridTextColumn Binding="{Binding OrderID}"
HeaderTemplate="{StaticResource headerTemplate}" />
Or use
<Window.Resources>
<TextBlock x:Key="TextBlockName" Height="50"
Text="{DynamicResource firstName}"
TextWrapping="Wrap" />
</Window.Resources>
and
<DataGridTextColumn Binding="{Binding OrderID}"
Header="{StaticResource TextBlockName}" />
In this first approach we are setting style with the help of header template, and in the second one we are setting it with the help of static resource.
I hope this addresses your question, in such a case we can close it.
@anjalisheel-wpf this does not address the fact that the DynamicResource extension does not work on DataGridColumn.
Hi @anjalisheel-wpf,
Sorry for the delay,
The provided workaround does not satisfy our requirements. Our need is to achieve this requirement in a simple way like the below,
HeaderText={DynamicResource something}.
Hi @miloush,
Sorry for the delay.
Seems the mentioned PR is still in progress. When we expect the fix for the reported issue
Why is "simple way" a requirement? I am not doing any more work on the PR, I was looking for more feedback on whether that is a reasonable way to support this scenario.
Hi @miloush,
The purpose of requesting the simple way to access the property that is bound for HeaderText is a very simple comparatively process with HeaderTemplate
I know this issue was last updated long ago but I ran over this problem today. This is the simpliest way to solve this I found.
<DataGrid.Columns>
<DataGridTextColumn>
<DataGridTextColumn.Header>
<TextBlock Text="{DynamicResource gridColumnHeader1}" />
</DataGridTextColumn.Header>
</DataGridTextColumn>
</DataGrid.Columns>