I have a class library I am creating for an AutoCAD plugin that includes WPF control elements. I would like to add a theme to these elements, so I added the WPFThemes.DarkBlend package from Nuget.
To property utilize the theme, you are supposed to add the style reference to your App.xaml file like so:
<Application
...
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes\Styles.xaml” />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>
Now unfortunately, because this is only a class library, I do not have an App.xaml file in which to add this code. I am able to use my Window.Resources, but in doing so, I am afraid that the styles in the reference are not exposed to the Window element. Is this because the Window is not within the scope of its own resources? Below is an image that shows my current situation:
Thank you!
After creating an x:Key in the style called "DarkWindow", I found that I was able to apply the style directly in the PluginWindow.xaml window properties like this:
<Window Style="{DynamicResource DarkWindow}" />
Related
My project uses a ProjectTheme.xaml file for all WPF windows through out the project.
The ProjectTheme.xaml file references a style theme as follows
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<!-- In order to modify the project's theme, change this line -->
<ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Customized.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
All WPF Windows references WindowBase.xaml
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyProject;component/View/WindowBase.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
WindowBase.xaml references customized titlebar Bar1.xaml
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Bar1.xaml" />
</ResourceDictionary.MergedDictionaries>
Bar1.xaml references ProjectTheme.xaml
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="/MyProject;component/ProjectTheme.xaml"/>
</ResourceDictionary.MergedDictionaries>
So the heriarchy is
Window1 references WindowBase.xaml
WindowBase references Bar1.xaml
Bar1 references ProjectTheme.xaml
ProjectTheme.xaml reference the real theme resource file.
This works fine.
Now I want to dynamically change the project theme at run time without quitting the app.
Assuming that I have several theme style files
Customized.xaml
Customized1.xaml
Customized2.xaml
My question is
if it possible to dynamically update ProjectTheme.xaml file at run time to change the line
from
<ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Customized.xaml" />
to
<ResourceDictionary Source="/MyProject;component/Themes/WPFThemes/Customized1.xaml" />
to achieve my objective?
If yes, how do I do it?
If no, what is the reason and what is the best (other) way to achieve my purpose?
I have tried the following but none of them work: the style does not change.
way 1
Application.Current.Resources.MergedDictionaries.Clear();
Uri NewTheme = new Uri(#"/MyProject;component/Themes/WPFThemes/Customized2.xaml", UriKind.Relative);
ResourceDictionary dictionary = (ResourceDictionary)Application.LoadComponent(NewTheme);
Application.Current.Resources.MergedDictionaries.Add(dictionary);
way 2
Application.Current.Resources.MergedDictionaries.RemoveAt(0);
Uri NewTheme = new Uri(#"/MyProject;component/Themes/WPFThemes/Customized2.xaml", UriKind.Relative);
ResourceDictionary dictionary = (ResourceDictionary)Application.LoadComponent(NewTheme);
Application.Current.Resources.MergedDictionaries.Insert(0, dictionary);
Note:
In my real theme style files (Customized.xaml...) I used a combination of dynamic resource and static resource. Does that matters?
Thanks in advance.
There are a few things to consider here.
First, anything defined with StaticResource will not get updated on a change. If you want a control to support changing the theme at runtime, you need to use DynamicResource so it knows to look for changes.
Your overall approach to changing the theme is correct. The easiest way to accomplish this is using Application-scoped resource dictionaries, making sure your ResourceDictionary is defined in your App.xaml. For adding a new resource, I've used snippets similar to the following:
ResourceDictionary dict = new ResourceDictionary();
dict.Source = new Uri("MyResourceDictionary.xaml", UriKind.Relative);
Application.Current.Resources.MergedDictionaries.Add(dict);
The part you may be confusing yourself over is when using resources within base classes. When you define a resource in a class, the resource will be local to an instance of that type. Think of the XAML compiling into it's own InitializeComponent() method on classes, meaning you can't change the original XAML and expect the changes to go to all instances. On the same note, changing the resources on a class instance doesn't effect other instances.
Since your question really contains two separate concerns (application theming and changing control resources), I would focus on ensuring your application resources are updating properly and using DynamicResource, and hopefully the information I've provided would be sufficient for understanding why certain other resources may not be updating yet.
I have defined two resource dictionaries for controls which inherit from TextBox within my usercontrol like so:
<UserControl.Resources>
<ResourceDictionary Source="KeyBox.xaml" x:Key="KeyBox" ></ResourceDictionary>
<ResourceDictionary Source="kTextBox.xaml" x:Key="kTextBox" ></ResourceDictionary>
</UserControl.Resources>
I have created the styles in separate files with different target type:
<Style TargetType="b:kTextBox" >
Now when I create the controls using these resources only the style applied last actually gets applied, so if I remove the second the first works. There's something I am missing here to make use of two resources within the same usercontrol and I can't figure out what it is. Any ideas much appreciated.
Try adding your resource dictionaries like this:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="KeyBox.xaml" x:Key="KeyBox" ></ResourceDictionary>
<ResourceDictionary Source="kTextBox.xaml" x:Key="kTextBox" ></ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Note that unless you have a class named kTextBox, your Style wont work.
It's also worth mentioning that your control will only have one style applied at a time, and the last resource added to the dictionary will be applied. Therefore if you have a style defined in both of your dictionaries with the same key, the one from kTextBox.xaml will be applied.
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.
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
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.