ResourceDictionary Merge behaviour - wpf

In my project I am trying to embed source code from Avalon Wizard but there is something strange happening and I am not able to successful integrate it.
I have the following structure in my Custom control library
Wizard
Themes
Aero.NormalColor.xaml
Aero2.NormalColor.xaml
AeroWizardHeader.xaml
Generic.xaml
Wizard97.xaml
WizardAero.xaml
Generic.xaml
Themes
Generic.xaml
Inside my Generic.xaml I have the following delcaration
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CuratioCMS.Client.UI;Component/Wizard/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
and inside Wizard/Themes/Generic.xaml here is how I have my MergedDictionaries defined
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CuratioCMS.Client.UI;Component/Wizard/Themes/Wizard97.xaml" />
<ResourceDictionary Source="CuratioCMS.Client.UI;Component/Wizard/Themes/WizardAero.xaml" />
<ResourceDictionary Source="CuratioCMS.Client.UI;Component/Wizard/Themes/AeroWizardHeader.xaml" />
</ResourceDictionary.MergedDictionaries>
According to Avalon implementation there is one more MergedDictionary provided inside Aero.NormalColor.xaml which looks like this
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="CuratioCMS.Client.UI;Component/Wizard/Themes/AeroWizardHeader.xaml" />
</ResourceDictionary.MergedDictionaries>
My problem is that I am not able to use my own class library in my project as designer throws exception which is: Cannot locate resource 'wizard/themes/curatiocms.client.ui;component/wizard/themes/wizard97.xaml'.
If I change Path inside Wizard/Theme/Generic.xaml then error goes away but Wizard is not able to provide Aero functionality and even designer does not work ex expected.
Let me also say, that I decided to have this kind of architecture because according to extended WPF toolkit this is very clean way .
can anyone help me with this?

Have you tried using the full pack URI syntax?
Have you tried changing 'Component' to 'component'? Also make sure the dictionary has it's build action set to Resource and you are correctly referencing your CuratioCMS.Client.UI assembly.

Related

Multiple XAML resource files in one assembly, referenced in another assembly

Good evening. A WPF XAML resource question please.
I have one user-control project called Resources. In this project I have a directory that contains multiple XAML files. I have merged these resources in a Main.xaml file in the project root directory.
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Resources;component/xaml/Buttons.xaml" />
<ResourceDictionary Source="Resources;component/xaml/Images.xaml" />
<ResourceDictionary Source="Resources;component/xaml/Styles.xaml" />
<ResourceDictionary Source="Resources;component/xaml/Tooltips.xaml" />
</ResourceDictionary.MergedDictionaries>
The Resource project compiles without issue and there are no visual errors in the code you see above.
I have a second project called Buttons. In the App.xaml, I reference this Resource project.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources;component/Main.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
I have referenced Resources.dll in the Button project. Visual Studio displays an error line under the ResourceDictionary statement; howbeit the project compiles.
When I run Button.exe, I get the error "Cannot locate resource 'resources;component/xaml/buttons.xaml'."
My ResourceDictionary statement matches what I have successfully done in other projects. Assuming what I have written in App.xaml in the Button project is correct, what should I do differently in the Resources' Main.xaml file?
Thanks in advance.
Okay, I figured it out. I'll document how to do this in case anyone else runs across this.
In my one assembly entitled Resources, I have a Main.xaml file in the project root. I have a subdirectory entitled "xaml" where I have several xaml files. My mistake was in the leading backslash on the directory "xaml".
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="xaml/Buttons.xaml" />
<ResourceDictionary Source="xaml/Images.xaml" />
<ResourceDictionary Source="xaml/Styles.xaml" />
<ResourceDictionary Source="xaml/Tooltips.xaml" />
</ResourceDictionary.MergedDictionaries>
Then, in another project called Buttons, in the App.xaml file, I reference that Main.xaml file in the MergedDictionaries section.
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Resources;component/Main.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Once I corrected the references in the main file, everything works correctly.
So this allows me to split up my resources into separate xaml files and reference them in other assemblies. Wohoo!
Also, for completeness, for each of the xaml files (including main.xaml), set the Build Action to Page (right-mouse click on the xaml file and select Properties).

WPF Resource Dictionary in Excel Addin

I've been searching a while now and still no closer to a solution. Here's my situation:
I am creating an Excel Addin and want to use WPF to make it look a little better. Natively (as far as I know) Addins have to be WinForm. I started using WPF Element Hosting but the reult is not very good. I then found that adding a WPF Project to the solution works which is great, but now I want to use a Resource Dictionary to keep forms looking the same and reducing inline styles. I just cant get the merged dictionaries to work.
I have tried Pack URI and ;component/..... but neither work.
What am I doing wrong?
-------EDIT-------
I have a Excel Addin Solution called SolutionA
The solution contains 3 Projects:
ProjectA which is an Excel Addin Project which has references to ProjectB and ProjectC
ProjectB which is a WPF Project which has a reference to ProjectC
ProjectC which contains the resource dictionary
Just need to know how to reference the resource dictionary from ProjectB
Please take a look at the Pack URIs in Windows Presentation Foundation page on MSDN.
Basically, you want something a bit like this:
<ResourceDictionary Source=
"pack://application:,,,/AssemblyName;component/FolderName/DictionaryName.xaml" />
You will need to change AssemblyName to the name of the assembly that your resource file is in and FolderName to the name of any folder(s) that your resource file is in and then DictionaryName to the name of you resource file. Basically, it's just the relative path to your resource file.
I am developing an Excel document customization using WPF controls and MahApps styles. Everything works fine on my virtualized development box using Excel 2013 and a physical Excel 2010 box (both have VS2012 on them).
On other virtualized boxes running Excel 2010 or Excel 2013 the styles do not work. This is when running exactly the same code.
This is similar to the problem reported here and in this post.
I'll share my findings in case it is of help to you. From various testing it seems that if the MahApp resources are placed in the UserControl or Window, they work. However placing them in my own resource dictionary and loading that dictionary in the user control does not work.
e.g. this works
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
but
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/IressWorkbook;component/Assets/MyTheme.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
does not, where MyTheme contains
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:System="clr-namespace:System;assembly=mscorlib">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
I am trying to track down what the difference is between the machines that work and the ones that don't.
Regards
Alan
I made it work this way:
add dictionaries at runtime
wpfApp = new Application() { ShutdownMode = ShutdownMode.OnExplicitShutdown }; wpfApp.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml") }); wpfApp.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml") }); wpfApp.Resources.MergedDictionaries.Add(new ResourceDictionary() { Source = new Uri("pack://application:,,,/MahApps.Metro;component/Styles/Themes/Light.Blue.xaml") });
use DynamicResource in xaml
<ContentControl Foreground="{DynamicResource MahApps.Brushes.IdealForeground}" />
Works in VS2019 with net48 vsto excel addin with O365 local install version 16.0.+

Unable to merge ResourceDictionary from a referenced project

I have two assemblies that each provide a common set of styles and resources that I want to include in my application. I'm using merged dictionaries in my App.xaml in order to load them, and at runtime they were just fine. Unfortunately, these resources won't load at design time, filling my Errors window with messages about unresolvable resources and giving me a UI that doesn't represent what will actually appear.
This is my App.xaml as it stands right now:
<Application x:Class="ClientDebug.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/Dai.Common;component/Xaml/Common.xaml" />
<ResourceDictionary Source="/Dai.DevExpress;component/Xaml/Styles.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
For both of these merged dictionaries, I get the following errors in my Errors window:
Error 11 An error occurred while finding the resource dictionary "/Dai.Common;component/Xaml/Common.xaml". C:\DevProjects\Core Application\ClientDebug\App.xaml 12 17 ClientDebug
Error 12 An error occurred while finding the resource dictionary "/Dai.DevExpress;component/Xaml/Styles.xaml". C:\DevProjects\Core Application\ClientDebug\App.xaml 13 17 ClientDebug
Which are obviously short on helpful information. Again, they load at runtime just as you'd expect, but none of the resources are available at design time.
I have this every time I start a new WPF project or work with an old one ever since a few days ago. I started a question to ask for help on it, only for it to disappear on me on a test Solution! Seems Visual Studio's not very stable, who knew?
The core of the problem is that the Xaml designer isn't allowing you to make references to other Projects in your Solution from your Application Project only. The workaround is to move everything into a Library and have the Application do little more than hand off control to it in code. Inelegant and the loss of App.Xaml is very tough, but it's much better than waiting for Visual Studio to magically figure it all out.
I precede the dictionaries that are from other namespaces with "pack://application:,,," like so:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Wsi.Util;component/DataGrid/NameValueDataGridDictionary.xaml" />
<ResourceDictionary Source="LayoutStylesDictionary.xaml" />
<ResourceDictionary Source="pack://application:,,,/Wsi.Util;component/controls/ToolBarResources.xaml" />
<ResourceDictionary Source="pack://application:,,,/Wsi.Common;component/view/themes/FilterStylesResourceDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
HTH,
Janene
I tried a similar merging in a project of mine and I seem to have it working perfectly. (or so, forgive me if its some settings of mine that I may have set long ago..) The only question I can ask is if the xamls are referring to anything within the parent project? I am assuming you have a reference to the parent project also (just cross-checking). Maybe the xaml file needs another xaml file too (controls, colors, fonts etc).
(The merging that I tried was from MahApps.)
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colours.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Blue.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
I fixed this issue by signing the referenced project.
Problem was: My project was signed with a key file but the referenced project not.
To solve:
Load the project into the solution
Opened the project properties
Navigate to 'Signing'
Click 'Sign the assembly'
Select '<New...>' from the combo box
Enter a name, eg. 'keyfile' ('Protect my keyfile with a password' is optional)
Rebuild solution

Global style in a separate assembly

For my application themes, I created a separate class library MyApp.Themes.dll.
In the root folder of this library I have Standard.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="pack://application:,,,/MyApp.Themes;component/Standard/Accordion.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
In Standard folder I have Accordion.xaml:
<ResourceDictionary xmlns:layoutPrimitivesToolkit="..."
xmlns:layoutToolkit="..."
...>
<!-- layoutPrimitivesToolkit:AccordionButton -->
<Style TargetType="layoutPrimitivesToolkit:AccordionButton">
...
</Style>
...
</ResourceDictionary>
which are default styles for WPF Toolkit Accordion control, except that style for
AccordionItem is modified to set background to transparent (instead of blue, which is a known bug).
For both xaml files Build Action is set to "Resource".
Now, after referencing MyApp.Themes library in MyApp WPF project, in App.xaml I wrote the following:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="pack://application:,,,/MyApp.Themes;component/Standard.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
It doesn't work (no error; just style not applied). If I copy&paste Accordion.xaml styles directly in App.xaml, then it works.
Some people suggested adding dummy resource dictionary, so I added the following in App.xaml after MergedDictionaries ending tag:
<Style TargetType="{x:Type layoutToolkit:AccordionItem}" />
Again, it doesn't work. Can someone help me solve this? By the way, I didn't try an approach
suggested by some others - using basedOn. If I must do that, I'd like to do in MyApp.Themes,
because it makes using themes nicer in App.xaml. Thank you in advance.
UPDATE1: It works if I directly copy&paste Accordion.xaml content to Standard.xaml
UPDATE2: I tried local assembly resource file URI (http://msdn.microsoft.com/en-us/library/aa970069.aspx) in Standard.xaml:
<ResourceDictionary Source="pack://application:,,,/Standard/Accordion.xaml"/>
It throws an error, saying standard/accordion.xaml not found.
It seems there's a bug in .NET. See the thread below:
Trouble referencing a Resource Dictionary that contains a Merged Dictionary
Also, there's a connect page on Microsoft site:
https://connect.microsoft.com/VisualStudio/feedback/details/609601/merge-dictionaries-does-not-work-when-we-merge-merged-dictionaries#tabs

Trouble referencing a Resource Dictionary that contains a Merged Dictionary

I have a library, CommonLibraryWpfThemes, with several Resource Dictionary XAML files in it. My Themes/Generic.xml file contains a ResourceDictionary.MergedDictionaries declaration that merges all the other files together.
Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/BrushDictionary.xaml" />
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/TextBlockDictionary.xaml" />
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/LabelDictionary.xaml" />
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/ButtonDictionary.xaml" />
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/WindowDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
In my application project, I have a reference to CommonLibraryWpfThemes, and I explicitly reference Generic.xml in my App.xaml file.
App.xaml -- FAILS
<Application
x:Class="MyApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/Themes/Generic.xaml" />
</Application.Resources>
</Application>
This doesn't work. I get the following error when I run my app:
System.Windows.Markup.XamlParseException occurred
Message="Cannot find resource named '{_fadedOrangeBrush}'. Resource names are case sensitive. Error at object 'System.Windows.Setter' in markup file 'CommonLibraryWpfThemes;component/ResourceDictionaries/WindowDictionary.xaml' Line 18 Position 13."
Source="PresentationFramework"
LineNumber=18
LinePosition=13
If I place the contents of Generic.xaml into App.xaml directly, everything works fine:
App.xaml -- SUCCEEDS
<Application
x:Class="MyApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/BrushDictionary.xaml" />
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/TextBlockDictionary.xaml" />
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/LabelDictionary.xaml" />
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/ButtonDictionary.xaml" />
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/ResourceDictionaries/WindowDictionary.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Maybe I'm going about this in the wrong way. My goal is to make it easy to reference all my theme resources from multiple applications without having to list out all the individual files. Is there a recommended way to do this? (Note: I'm not trying to switch between multiple themes--I just have one theme.)
As a bonus, it would be nice if someone could tell me how to reference resources in an external library without breaking the designer in Visual Studio.
Thanks.
EDIT:
I tried wrapping the ResourceDictionary in a ResourceDictionary.MergedDictionary element, but that also didn't work (I get the same error):
<Application
x:Class="MyApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
</Application>
Answered a similar question here earlier, see Adding a Merged Dictionary to a Merged Dictionary question.
This is an optimization bug, see Microsoft Connect / DefaultStyleKey style not found in inner MergedDictionaries:
On the creation of every object in
XAML, if a default style is present
(i.e. style w/ a key of Type) that
style should be applied. As you can
imagine there are several performance
optimizations to make that (implied)
lookup a light weight as possible. One
of them is that we don’t look inside
Resource Dictionaries unless they are
flagged as “containing default
Styles”. There is a bug: if all your
default styles are nested in merged
dictionaries three levels deep (or
deeper) the top dictionary does not
get flagged so the search skips it.
The work around is to put a default
Style to something, anything, in the
root Dictionary.
So adding a dummy style to the root dictionary fixes this. Example
<Application x:Class="MyApp.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/Themes/Generic.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Dummy Style, anything you won't use goes -->
<Style TargetType="{x:Type Rectangle}" />
</ResourceDictionary>
</Application.Resources>
</Application>
Check your constructor in App.xaml.cs calls InitializeComponent() - this is what merges the resource dictionaries...
You should not have to reference generic.xaml at all, it has built-in support. This however means that it provides default styling, which you do not set explicitly. Explicitly set styles/templates need to be attainable from explicitly referenced res dictionaries.
(EDIT for clarity)
One exception to this is the App.xaml, where defined resources become accessible by the whole app, without requiring to reference any specific resource dictionary. The resource itself, would have to be accessible by name.
The reason why this fails
<Application.Resources>
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/Themes/Generic.xaml" />
</Application.Resources>
is, I think, because you didn't wrap it in a MergedDictionary wrapper, adding it to merged dictionaries. Adding directly to resources works only for resources you declare locally, e.g. the styles, etc. themselves.
However, as I said before, you shouldn't have to merge generic.xaml anywhere, maybe you should just refactor brushes and other resources used outside styles, and merge only those resources in app.xaml.
Also note that styles do not have to be in generic.xaml to have "default style" behaviour - if a style with key equal to the type of the element is accessible to it (globally, or in local resources), then it will use the style as a default style. The generic.xaml is just a convenience.
Check this answer.
For other custom brushes, etc, you need to reference those resources explicitly.
You should also check the contents of the WindowDictionary.xaml, this error has a certain smell about it.
I was getting this error in my unit tests and Chris' answer from above gave me the clue I needed. Basically on my first tested method, I put:
MyApplication.App app = new MyApplication.App();
app.InitializeComponent();
And suddenly it could find my template for my pages. Note: this does mean that you have to check to see if an instance of your App already exists if you are unit testing your App.cs as well.
My solution is here, click Workarounds.

Resources