Welcome to WindowsClient.net | My Blog | Sign in | Join

Rob Relyea - XAMLified

WPF, Silverlight and XAML

Syndication

Sponsors





  • advertise here
My StaticResource reference worked differently with WPF 4 RC than it does with WPF 4 RTM

We got a customer question about a change in behavior between WPF 4’s Release Candidate and WPF 4’s final version (RTM).

We discovered late in WPF4 a change in behavior since WPF 3.x that affected StaticResource lookup. In v3.x, we would always determine what a StaticResource resolved to (which exact value in which resource dictionary should be the answer to the {StaticResource} execution) during parse time.

We discovered in WPF 4 Beta1 until WPF 4 RC, we would determine the result more dynamically…which means differently.

We worked hard near the tail end of WPF 4 to put things back in a compatible place. For those people who did a bunch of coding on top of WPF 4 during WPF 4’s development, you may have been allowed to structure your XAML in certain ways that shouldn’t have worked.

Here is a write up from Brian (the XAML dev who spearheaded the fix) that may be helpful, if this bit you:

Forward Reference:

<ResourceDictionary>
     <Foo  x:Key=”AAA”  MyProperty=”{StaticResource BBB}” />
     <Bar  x:Key=”BBB” />
</ResourceDictionary>

RULE

StaticResource BBB cannot (should not) resolve forward to the x:Key=”BBB” entry.

Reason this is the right behavior

Forward references don’t work in XAML loaded as Text because StaticResources are executed when they are found and the key “BBB” is not present yet.

Why there is a problem

In the Compiled case the dictionary is read in as a big binary blob with a table of content so without counter measures the StaticResource would resolve to forward keys and we have an incompatibility with text and 3.5.

Reaching across Merged Dictionaries.

<ResourceDictionary>
   <ResourceDictionary.MergedDictionaries>
       <ResourceDictionary Source=”Xaml_1.xaml” />
       <ResourceDictionary Source=”Xaml_2.xaml”/>
   </ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

RULE

StaticResource’s in Xaml_2.xaml cannot (should not) resolve to x:Key’s found in Xaml_1.xaml.

Reason this is the right behavior

Each “Source” is a separate XAML file load and the outer Resource Dictionary is not on the parse stack and thus the keys in the other Dictionaries are not visible to the StaticResource lookup.

Why there is a problem

In the Compiled case entries in Resource Dictionaries are read and loaded later and the when they are loaded the context can be “more loaded” and the keys are visible.   But this would be impossible to recreate reliability in all situations and would never work in Text load.

Injecting resources after Loading XAML.
RULE

Modifications to the Resource Dictionary made after InitializeComponent() should not affect StaticResource lookups.

Reason this is the right behavior.

In a text load all Static Resource lookup are at executed as they are found.  So following the text model (like 3.5) all Static Resource lookup will be finished by the time InitializeComponent() returns.   And changing values in application code should have no affect.

Why there is a problem

In the compiled case Resource Dictionaries are lazily evaluated when referenced (for performance).  And thus changes to the Dictionary (and parent dictionaries) can change the result of Static Resources lookup.   This is incompatible with Text loading and also very dependent on exactly when the lazily evaluation takes place.

The Fix to WPF

The solution to this problem as is so often the case was "more code”.  The evaluation of entries referred to by StaticResources are still lazily deferred, but the locating and binding to the location of the entries is done eagerly and at load time.  And if any of the entries are overwritten by application code, a copy is made to preserve the value the StaticResource should receive when it is eventually evaluated.   There is separate code to handle inline templates (templates defined outside of resource dictionaries), but the same principles apply.

Published Monday, April 26, 2010 5:36 PM by Rob_Relyea
Filed under: ,

Comments

# Dew Drop &#8211; April 27, 2010 | Alvin Ashcraft&#039;s Morning Dew@ Tuesday, April 27, 2010 9:18 AM

Pingback from  Dew Drop &#8211; April 27, 2010 | Alvin Ashcraft&#039;s Morning Dew

# re: My StaticResource reference worked differently with WPF 4 RC than it does with WPF 4 RTM@ Wednesday, April 28, 2010 1:57 PM

Reaching across merged dictionaries works in WPF 3.5 if the dictionaries are being merged into App.Resources in App.xaml. Will it not work in 4.0?

by Koustubh Moharir

# re: My StaticResource reference worked differently with WPF 4 RC than it does with WPF 4 RTM@ Wednesday, April 28, 2010 11:47 PM

Koustubh-

We discovered a break late in the game in v4 in this general area.

Can you try putting a <Style TargetType="someType" /> in <Application.Resources>... i think that works around the bug...

Let me know either way, I need to write that one up more formally...

Thanks, Rob

# re: My StaticResource reference worked differently with WPF 4 RC than it does with WPF 4 RTM@ Friday, April 30, 2010 1:23 PM

I tried out the following scenario in WPF 4.0 and it works the same as in 3.5.

ResourceDictionary1 contains resource1.

ResourceDictionary2 contains resource2 with a StaticResource reference to resource1.

Both dictionaries are merged into Application.Resources

Window1 has something with a StaticResource reference to resource2.

All StaticResource references are resolved correctly. [If the dictionaries are merged into Window.Resources instead, the resource1 reference fails silently.]

by Koustubh Moharir

# re: My StaticResource reference worked differently with WPF 4 RC than it does with WPF 4 RTM@ Wednesday, May 12, 2010 7:50 PM

Rob's suggestion worked perfectly.

Adding:

<Style TargetType="{x:Type Window}"/>

in my base resource dictionary fixed the issue.

it now looks like:

<ResourceDictionary>

   <ResourceDictionary.MergedDictionaries>

     <ResourceDictionary Source="LookAndFeel.xaml"/>

   </ResourceDictionary.MergedDictionaries>

   <Style TargetType="{x:Type Window}"/>

 </ResourceDictionary>

and everything started working as expected.

by Brian

# re: My StaticResource reference worked differently with WPF 4 RC than it does with WPF 4 RTM@ Thursday, June 17, 2010 9:15 AM

I have tried this workaround but it didn't works

by Alex

Leave a Comment

(required) 
(required) 
(optional)
(required)