Override Control Style - wpf

I have created a CustomControlLibrary.dll, that contains a Control (MyControl), with its style in the Generic.xaml of the Themes folder, as per the default automatic setup.
If I want to include that dll in 2 different projects, each of which providing a custom style for "MyControl" to give it a different look, where do I put those custom styles?
I thought I just had to have a Themes\Generic.xaml for each application, that defines the custom style, but having done this, it still ends up using the style defined in CustomControlLibrary.dll

You have CustomControlLibrary.dll which is the owner of MyControl. Inside that dll you have your themes defined. Any other project that may contain your dll doesnt haven to have themes defined.
Other projects may define their custom style for MyControl in their window resource for example.
Styles may be defined at any level. :)
Check this link out:
http://msdn.microsoft.com/en-us/library/ms745683.aspx

Solution will be to define specific style for each project and apply it correspondingly.
But keep in mind that you can create proper style "inheritance" by using BasedOn property. After all you should get a set of styles that you'll manage in MergedDictionaries:
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/CustomControlLibrary;component/styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

Related

How to make a globally available style WITHOUT App.xaml

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}" />

WPF Dynamically change resource file and theme

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.

WPF Resource access from a different assembly if no App.xaml

I have am creating a WPF extension to an existing Win32 MFC client application. Within a UserControl located in my WPF class library, I am merging libraries as follows:
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="MyResourceDLL;Component/dictionaries/styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
I also tried
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/MyResourceDLL;Component/dictionaries/styles.xaml"/>
</ResourceDictionary.MergedDictionaries>
In either case, I get the following XamlParseException:
System.Windows.Markup.XamlParseException
occurred
Message="MyResourceDLL;Component/dictionaries/styles.xaml'
value cannot be assigned to property
'Source' of object
'System.Windows.ResourceDictionary'.
Cannot locate resource
'ems.wpf.resources;component/dictionaries/styles.xaml'.
Error at object
'System.Windows.ResourceDictionary' in
markup file
'SARMaster.Maryln.EphemerisLib;component/getephemeriscontrol.xaml'
Line 9 Position 37."
I there a way I can load a relative DLL that is not referenced by main project?
I've been looking at the same issue recently. When compiling a Win32 CLR project the dependencies of the assemblies referenced by the MFC project aren't copied, so I simply set up a post-build event to copy the appropriate assemblies to the $(TargetDir).
Not ideal, but I believe it's by design.
I got the same problem and I found the solution. I needed to remove the Style of my ContentPresenter. This line was creating the XamlParseException:
<ContentPresenter.Resources>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource TextStyle}"/>
</ContentPresenter.Resources>
And after fixing this error, I needed to do these steps to have something 100% working:
Here my projects:
StyleProject: the Class Library project that I want to use. It contains my styles
MainProject: the project that will use the styles
To do so:
Add the reference of my StyleProject inside my MainProject (see here)
Create a ResourceDictionary called MyStyle.xaml inside my MainProject
Add the different dictionaries of my StyleProject following this answer to MyStyle.xaml
Add MyStyle.xaml to the App.xaml using the following code
Code:
<ResourceDictionary Source="Resources/MyStyle.xaml"/>

WPF custom View without Generic.xaml

I am trying to implement custom views that are specific to an application without any luck. Here is my problem:
I need a custom view because I would like for the user to be able to switch views dynamically at runtime. I need a custom view (as opposed to only datatemplates) because the listview layout has to change as well as the Control template and the data template.
All of the turorials say to implement Custom classes that derive from viewbase and override the DefaultStyleKey and ItemContainerDefaultStyleKey to return a ComponentResourceKey defined in generic.xaml. However, the problem is that I am trying to create several views that are very specific to that application. certain brushes and fonts will be consistant accross the application and the custom views will use these. i.e. I have application level Forebrush, Shadowbrush, Deepshadowbrush, TextDecorator, etc. and I want the views to use these. If the view will be defined in an external generic.xaml it will be very convoluted markup to bind to these. And besides, it would make them application specific anyway (if they bind to these brushes).
Anyone have an idea how to define styles for views internaly in the application that will be able to be changed at runtime?
I'm slightly confused on your details, however you can set the Style of a ListView at runtime as such...where CustomStyle is a predefined style that you want to apply to the ListView.
ListView view = new ListView();
view.Style = CustomStyle;
The DefaultStyleKey is applicable to a custom Control (this is different then a UserControl). So say you want a new Control called a Widget. You would need ot define the DefaultStyleKey for that Widget since it does not have a default style defined. A UserControl is a collection of Controls, therefore it does not have a pre-defined style as such.
In addition you can create a ResourceDictionary to break apart your styles. You can then merge them via the App.xaml as such...
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Themes/Generic.xaml"/>
<ResourceDictionary Source="Themes/ListViewStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Application.Resources>

Basing On a style defined inside a custom control library

I'm extending the available WPF's TreeView control.
I wish to add to it CheckBox behavior like Josh Smith has suggested.
My goal is to encapsulate all checkbox behavior concerns from the end user (which is a different approach of what Josh Smith has done).
I would like to use a style for the TreeViewItem in order to add some properties and bindings as described in the article.
So I have created a style, pushed him to the generic.xaml and called it TreeViewItemStyle.
My requirement is that I still wish that the end user can add a style (for colors and theme) on his own.
One way to do that is using the BaseOn property of the style, but it must use StaticResource and it fails to find my style, TreeViewItemStyle.
Is there a workaround? Is it actually a good approach?
What do you do?
Ariel
Did you include the generic.xaml file in the new resource dictionary you are trying to create?
<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:,,,/ASSEMBLY;component/Resources/generic.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style x:Key="NewStyle" BasedOn="{StaticResource TreeViewItemStyle}">
</Style>
</ResourceDictionary>

Resources