Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataTemplate key is ignored when specified with x:Static

Tags:

c#

wpf

xaml

I encountered weird behavior with DataTemplate keys: when DataType is specified via x:Type, and x:Key is specified via x:Static reference, x:Key is ignored. I wrote sample app to illustrate it.

XAML resources:

<DataTemplate DataType="{x:Type wpfApplication1:TestDto}" x:Key="{x:Static wpfApplication1:DataKeys.TestDtoKey}" />
<DataTemplate x:Key="{x:Static wpfApplication1:DataKeys.TestDtoKey2}" />
<DataTemplate DataType="{x:Type wpfApplication1:TestDto}" x:Key="TestKey3" />
<DataTemplate DataType="wpfApplication1:TestDto" x:Key="{x:Static wpfApplication1:DataKeys.TestDtoKey4}" />

C#:

public class TestDto {}

public static class DataKeys
{
    public static string TestDtoKey = "TestKey";
    public static string TestDtoKey2 = "TestKey2";
    public static string TestDtoKey4 = "TestKey4";
}

Launch application, see this.Resources.Keys in debugger:

{DataTemplateKey(WpfApplication1.TestDto)}  object {System.Windows.DataTemplateKey}
"TestKey2"  object {string}
"TestKey3"  object {string}
"TestKey4"  object {string}

As you can see, in first case x:Key is ignored!

Can someone explain what is going on? Documentation (http://msdn.microsoft.com/en-us/library/system.windows.datatemplate.datatype.aspx) clearly says that setting x:Key will set resource key to whatever you specify in it.

like image 260
Pavel Tupitsyn Avatar asked Oct 18 '13 14:10

Pavel Tupitsyn


2 Answers

Short answer to your question is - YES it's a bug in WPF framework. Bug reported here.

Update -

Microsoft has accepted that it's a bug in XAML compiler and they are not fixing this issue. Quote from Microsoft -

This is an issue in the XAML compiler - it produces BAML to describe the key for each resource, normally based on the x:Key if it's present and on the DataType if it's not. When x:Key is itself indirect (in your case, using x:Static), the compiler chooses the DataType key. While choosing the x:Static-based key is probably more "correct", changing this would introduce compatibility issues. Also, because the issue occurs at compile-time, you'd have to recompile your app to see the fix (to generate a different BAML stream). Existing copies of your app would contain the old BAML stream, and would behave the same way at runtime as they do now. For this reason we are deciding to won't fix this issue.

x:Key is not ignored here but is set to DataTemplateKey(WpfApplication1.TestDto) in first case. You cannot have a resource declared under Resources section without a key value.

As you can see that key gets automatically set to DataTemplateKey(WpfApplication1.TestDto) here.

From MSDN -

This property that is very similar to the TargetType property of the Style class. When you set this property to the data type without specifying an x:Key, the DataTemplate gets applied automatically to data objects of that type. Note that when you do that the x:Key is set implicitly. Therefore, if you assign this DataTemplate an x:Key value, you are overriding the implicit x:Key and the DataTemplate would not be applied automatically.

Somehow, in case you bind x:Key with static value instead of hardcoding string, it gets defined as default template for that dataType and hence key gets set to DataTemplateKey(WpfApplication1.TestDto).

This you can verify by adding another DataTemplate to your resources with only DataType set i.e.

<DataTemplate DataType="{x:Type wpfApplication1:TestDto}"/>.

It will compile fine but will throw runtime error

"Item has already been added. Key in dictionary: 'DataTemplateKey(WpfApplication1.TestDto)' Key being added: 'DataTemplateKey(WpfApplication1.TestDto)'"

like image 157
Rohit Vats Avatar answered Oct 21 '22 19:10

Rohit Vats


Im not shure that will help, but try to append {get;set;} to each property in your class. Some staff in WPF (i.e. Binding) does not works without them. May be here is the same story...

public static class DataKeys
{
  public static string TestDtoKey { get { return "TestKey"; } set; }
  public static string TestDtoKey2 { get { return "TestKey2"; } set; }
  public static string TestDtoKey4 { get { return "TestKey4"; } set; }
}
like image 39
Anatoly Nikolaev Avatar answered Oct 21 '22 18:10

Anatoly Nikolaev