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.