I came across this oddity while trying to resolve issues using merged ResourceDictionaries in a WPF app I'm working on.
I have custom controls (TextButton, MenuButton) and resources (colors, brushes, control styles and custom control templates) defined in an external DLL ("common"). In another library I have a user control that uses these styles ("pluginA").
As long as I was working with the standard WPF controls (TextBlock, Button, Grid etc.) - I could apply the styles from the "common" dll without any problems. The designer would pick up the style and apply it correctly.
If I plop in one of the custom controls (TextButton) into the User Control in "pluginA" - the designer would find the custom control, but couldn't resolve the type for the style to be applied (Type reference cannot find the type named '{clr-namespace:Common}TextButton').
The xmlns declaration in my usercontrol looks like this:
<UserControl x:Class="PluginA.Views.LeftBarView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:core="clr-namespace:Common.Core;assembly=Common"
xmlns:common="clr-namespace:Common;assembly=Common"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="300">
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<core:SharedResourceDictionary Source="/Common;component/Resources/DefaultTheme/DefaultTheme.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
With this definition, the designer doesn't apply any styles - but it works in runtime. Great, but not quite that helpful as I don't want to run the application to see if a minor tweak took effect.
So I tried this:
<core:SharedResourceDictionary Source="pack://application:,,,/Common;component/Resources/DefaultTheme/DefaultTheme.xaml" />
But that didn't change anything (designer still wouldn't find the resources). In the process of changing the code, I got to this:
<core:SharedResourceDictionary Source="pack:/Common;component/Resources/DefaultTheme/DefaultTheme.xaml" />
Now the designer is happy and can find the resources - runtime is happy and displays the resources, and yet I can't find any description of this being a valid PACK URI... Can anyone explain why this would work?
This is technically a valid URI, but it is not a valid
packURI. Parsing it according to the rules of thepackformat would yield:Package URI:
<empty>Part URI:
/Common;component/Resources/DefaultTheme/DefaultTheme.xamlIn effect, you have made an absolute URI out of a part URI by appending the
pack:scheme. However, without a well-formed package component, the result is not a validpackURI. And, interestingly, theUriclass will not actually parse the original string as an absolute URI; it is parsed incorrectly as a relative URI, and that is part of the reason it works when assigned toResourceDictionary.Source. Let's take a look at the property setter:The key lies within
BindUriHelper.GetResolvedUri(_baseUri, _source). The logic there, which differs from much of thepackURI handling in WPF, sees that_sourceis not an absolute URI (at least according to the brokenUriclass), so it attempts to combine it with the resolved base URI, which we presume to bepack://application:,,,/. The URIs are combined vianew Uri(Uri baseUri, Uri relativeUri), which works only becauseUriincorrectly parsed the original string as a relative URI. The URI which ultimately gets used to create theWebRequestis equivalent to:...which produces:
And viola, we end up loading the resources from a valid pack URI even though we gave it an invalid one.
We know that the "bad" URI works because it gets accidentally transformed into a good one. As to why that same "good" URI not work in the designer when it's used directly, that is very curious.
Perhaps you simply need to rebuild both the
Commonproject and the project that is attempting to merge the resource dictionary. If it still fails, then it's possible yourUserControl.Resourceshas a differentBaseUriwhen running in the designer than it does at runtime. Let's see if we can figure out what theBaseUriis at design time. Modify yourUserControlas follows:See what gets displayed in the designer. It may give us a clue.