please explain what is themes and generic.xaml? [duplicate] - wpf

I've been trying to figure out how to organize my ResourceDictionary files for reuse and sharing with other members of my team.
I keep coming across "Generic.xaml", but if I look on MSDN for Generic.xaml or just do a Google search, I only seem to get blog posts and forum questions that happen to mention it--I can't seem to hit upon anything really authoritative and clear.
What is the difference between Generic.xaml and MyRandomlyNamedResourceDictionary.xaml? It seems like either way, I have to reference ResourceDictionaries stored in libraries with the Source attribute. E.g.,:
<Application.Resources>
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/Themes/Generic.xaml"
</Application.Resources>
So what advantage does Generic.xaml provide exactly? Does it have any purpose if I'm not trying to give my application multiple "looks" (i.e., if I have only one theme)?

Every Control in WPF has a default Style that provides, among other things, the Control's default ControlTemplate. WPF looks for the default style in a special resource dictionary in the Themes folder in the same assembly as the control. The key for the default style is provided by the Control.DefaultStyleKey dependency property, the default value of which is overridden in each sub-class of Control.
The name of the resource dictionary depends on the current Windows theme e.g. on Vista using the Aero theme, the dictionary is called Aero.NormalColor.xaml, on XP using the default theme it is Luna.NormalColor.xaml. If the style is not found in the theme dictionary, it looks in Generic.xaml i.e for controls whose look doesn't depend on the theme.
This only applies to any custom controls you have defined i.e. classes derived from Control, directly or indirectly. You can change the default style for a standard control by deriving from it and calling DefaultStyleKeyProperty.OverrideMetadata in the static constructor, but you then have to supply the full style including ControlTemplate.
Note that you can tell WPF to look in an external assembly for your default style by using the ThemeInfo attribute. The external assembly must be named <YourAssembly>.<ThemeName>.dll e.g. PresententationFramework.Aero.dll.

For a generic.xaml file (case insensitive) to be something special, two conditions must be met:
It must be in the Themes sub-root folder in the project
The assembly must be marked with the ThemeInfoAttribute (usually in AssemblyInfo.cs)
Then it serves as the default lookup location for any default styles you wish to apply to your Controls. Note also that for a style to be the default it must declare both its TargetType and x:Key as the Type of Control which is to be styled.
If you wish to add entire themes and theme switching to your application, that is accomplished with some coding, this technique merely defines the default resource dictionary.

Related

Difficulties with ThemeInfo in WPF?

I am stuck with ThemeInfo attributes inside my AssemblyInfo.cs file. I am trying to write a custom control. The custom control is in a dll called "MyCustomControls.dll". Futhermore the control itself derives from another custom control which is inside another dll called "MyAnotherCustomControls.dll".
I read on MSDN that ThemeInfo must be declared with 2 parameters responsible for control theme specific location and generic specific location, though I have no idea what is "theme" and what "generic". How can I understand those two better?
If somebody could explain me an example from scratch what is "generic" and what "theme". Futhermore when to use "generic" or "theme". How are those two used by WPF system at all? I really need an explaination in plain english so please save your time if you are about to post me an MSDN link. I read msdn documentation about ThemeInfo and I dont get it.
Also can somebody please tell me how to just by using ThemeInfo tell my "MyCustomControls.dll" to use dictionary resources defined in "MyAnotherCustomControls.dll"? Is that even possible to do just by ThemeInfo or do I have to deal with MergedDirectories in "MyCustomControls.dll"? I would like the WPF system take care of locating resources so that I can use style keys from "MyAnotherCustomControls.dll"without the need to add merged directory in "MyCustomControls.dll".
I read on MSDN that ThemeInfo must be declared with 2 parameters responsible for control theme specific location and generic specific location, though I have no idea what is "theme" and what "generic". How can I understand those two better?
Basically the WPF framework will look for a xaml resource whose name matches the OS theme name. So if you're running on XP with the blue theme that will be "luna.normal.xaml". If it does not find one with that exact name, it will look for the "generic.xaml". In actuality I think they look for the "classic.xaml" first if they don't find one that matches the OS specific one and then they look for generic.xaml. You can think of the generic.xaml as the default resources.
The ThemeInfo attribute simply tells WPF where those resources are defined. There are 3 options:
None - You aren't providing either the "theme" or "generic" resources. This is really an optimization so the WPF framework doesn't bother looking for them. You wouldn't typically use this for the GenericDictionaryLocation but you might use this for the ThemeDictionaryLocation in case you weren't going to define OS theme specific resources (i.e. you didn't want your control to look different under different OS themes). Typically control vendors will define a resource dictionary for each possible OS theme so that the controls look consistent with the other controls and windows running in that operating system.
ExternalAssembly - This means that you are defining a separate assembly for the resources. So if you look at the WPF framework you will see that they use this for the PresentationFramework assembly for the ThemeDictionaryLocation. Then they defined a separate assembly for each OS theme they want to support (e.g. PresentationFramework.Aero.dll, PresentationFramework.Luna.dll, etc.). The name of the assembly it will search for is the name of the defining assembly plus the name of the theme.
SourceAssembly - This means that the resources are defined within the assembly itself. So in that assembly you would have a "themes" folder which contains the resource dictionaries.
This article on MSDN about control authoring really isn't that bad about providing information about this.
Also can somebody please tell me how to just by using ThemeInfo tell my "MyCustomControls.dll" to use dictionary resources defined in "MyAnotherCustomControls.dll"? Is that even possible to do just by ThemeInfo or do I have to deal with MergedDirectories in "MyCustomControls.dll"? I would like the WPF system take care of locating resources so that I can use style keys from "MyAnotherCustomControls.dll"without the need to add merged directory in "MyCustomControls.dll".
You can't use ThemeInfo to tell WPF that it should look for your resources in some arbitrary assembly. That being said if you don't set or override the DefaultStyleKey, as is typically done when defining a custom control, then it should continue to use the resources for the base class that did have its DefaultStyleKey set/overridden for the default resources.
It should be noted however that local Style resolution (i.e. when the Style property of your control is not set and WPF looks from the place at which the element is sited and walks up the visual/logical tree looking for a Style that might implicitly affect that element) will always look for Style whose Key matches the exact type of the class. So if have a Style whose TargetType (and therefore the default Key when that is placed in a ResourceDictionary) is TextBox defined in the Resources of your Window, it will affect all TextBox instances within that Window (unless they have a Style closer in the visual tree - i.e. defined in the resources of an element between itself some ancestor - or its Style property is set). However, if you have a class that derives from TextBox (e.g class MyTextBox : TextBox) then it will not pick up/use that Style. Instead it will be looking for a Style whose TargetType/Key is typeof(MyTextBox). One way to hack around that would be to set the Style property to a DynamicResource to the base type. e.g.
public MyTextBox()
{
this.SetResourceReference(StyleProperty, typeof(TextBox));
}
Basically this sets a local value on the control's Style property that is doing a dynamic resource lookup for a Style whose Key (and therefore TargetType for Styles where the x:Key is not set) is the specified type (TextBox in this case).
As you noted the alternative is to define the xaml files locally in your assembly for each theme that the base class' assembly defines and then add a ResourceDictionary to its MergedDictionaries that uses the pack uri notation to reference the resources in the base class's assembly. If you are setting the DefaultStyleKey then you will likely need to define a Style whose TargetType is your class' type in each of those ResourceDictionaries and then set the BasedOn to a StaticResource where the resource key is the type of the base class. It sounds though like you shouldn't need to do this.

How do I "merge" or use a system assembly's ResourceDictionary in my generic.xaml?

I specifically want to be able to leverage some of the system theme templates and definitions (colours and brushes) for my own custom control. I "think" I'm supposed to use the element in my generic.xaml's root element.
Considering I'm supposed to use some kind of path for the "Source" attribute, what would the path look like for "Aero2"?
Is this even accepted use? Am I allowed to use system themes?
Edit: Since this is a common theme of questions, here are a few other references.
How can I set a WPF control's color to a system color programmatically, so that it updates on color scheme changes?
Get Aero Window Colour
My goal is to use colours as defined in other ResourceDictionaries -- since they don't seem to match the "SystemColors" namespace.
See here.
Basically you need this:
<ResourceDictionary
Source="/PresentationFramework.Aero, Version=3.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35, ProcessorArchitecture=MSIL;component/themes/aero.normalcolor.xaml" />

Overriding some theme styles and properties per module

I am writing a WPF application using "Prism", and some purchased Grid theme is applied "Xceed Theme." I am designing a huge change required by our customer to give them the option of modifying some properties (like the background of selected row, for example) and this functionality to be available per screen "Module."
So my questions are:
After adding my xceed grid theme source to my App.xaml merged dictionaries, how can I override some of its styles (that I know the keys of) in another xaml file away from app.xaml (possibly by adding BasedOn to the style tag)?
Is it possible to create a custom resource dictionary for each module and add it to the app.xaml merged dictionaries while loading?
You could add the style changes in the main window/control's resources within each module. Then the differences would apply to each module separately.
In my case, I have userd Dynamic Resources. The main project loads the main style. somthing like this :
<FontFamily x:Key="ApplicationFontFamily">Tahoma</FontFamily>
and in my module i have changed it programmatically :
Application.Current.Resources["ApplicationFontFamily"] = new FontFamily("Arial");
it worked for me ;)

WPF: Applying a custom theme (skin) to a custom control

I have an application set up so that I can adjust its skin at run time. I am doing it as follows each time I change the skin:
Uri uri = new Uri("SomeThemeAssembly;component/Themes/StandardTheme.xaml", UriKind.Relative)
Application.Current.Resources.MergedDictionaries.Clear();
ResourceDictionary resource = (ResourceDictionary)Application.LoadComponent(uri);
Application.Current.Resources.MergedDictionaries.Add(resource);
This works fine.
I have also created a custom control with its controltemplate defined in Themes/Generic.xaml using ComponentResourceKeys for the relevant resources, etc
x:Key="{ComponentResourceKey
TypeInTargetAssembly={x:Type local:MyCustomControl},
ResourceId=MyBrush}"
The style of the custom control itself doesnt use a componentresourcekey as I want it to style all instances.
<Style TargetType="{x:Type local:MyCustomControl}">
Again this all works fine and standard controls I have used to compose elements of my custom control are appropriately styled when I change the skin.
However there are a number of custom properties( brushes, widths, etc) on my control that need to be styled to fit in with the skins I am applying.
In examples I have seen using the standard windows themes adding an additional file
Luna.StandardColor.Xaml
for example, to the themes directory of the custom control allows a modified control template to be set and picked up when that particular theme is applied. This won't work for me, as far as I can tell anyway, as my skins are not themes.
Can something similar be achieved when using 'skins' in the manner I have?
Obviously I can add Styles and ControlTemplates to my skin assemblies but this feels wrong especially as there is a standard naming convention across the skin assemblies for resources. So only a single more maintainable style would be required if it could be stored in Themes/StandardTheme.xaml in my custom control's assembly.
Having tried to read around on this subject I have the impression want I want to do is either impossible or will require loads of extra leg work.
Any thoughts appreciated.
In the CustomControls Themes Directory add a MyNewTheme.xaml file that's a resource dictionary that has an implicit style set for your control. Then merge that resource dictionary in with your other one as needed. For example:
Uri uri = new Uri("SomeThemeAssembly;component/Themes/MyNewTheme.xaml", UriKind.Relative)
Uri controlsUri = new Uri("ControlAssembly;component/Themes/MyNewTheme.xaml", UriKind.Relative)
Application.Current.Resources.MergedDictionaries.Clear();
ResourceDictionary resource = (ResourceDictionary)Application.LoadComponent(uri);
Application.Current.Resources.MergedDictionaries.Add(resource);
ResourceDictionary resource = (ResourceDictionary)Application.LoadComponent(controlsUri);
Application.Current.Resources.MergedDictionaries.Add(resource);

What is so special about Generic.xaml?

I've been trying to figure out how to organize my ResourceDictionary files for reuse and sharing with other members of my team.
I keep coming across "Generic.xaml", but if I look on MSDN for Generic.xaml or just do a Google search, I only seem to get blog posts and forum questions that happen to mention it--I can't seem to hit upon anything really authoritative and clear.
What is the difference between Generic.xaml and MyRandomlyNamedResourceDictionary.xaml? It seems like either way, I have to reference ResourceDictionaries stored in libraries with the Source attribute. E.g.,:
<Application.Resources>
<ResourceDictionary
Source="/CommonLibraryWpfThemes;component/Themes/Generic.xaml"
</Application.Resources>
So what advantage does Generic.xaml provide exactly? Does it have any purpose if I'm not trying to give my application multiple "looks" (i.e., if I have only one theme)?
Every Control in WPF has a default Style that provides, among other things, the Control's default ControlTemplate. WPF looks for the default style in a special resource dictionary in the Themes folder in the same assembly as the control. The key for the default style is provided by the Control.DefaultStyleKey dependency property, the default value of which is overridden in each sub-class of Control.
The name of the resource dictionary depends on the current Windows theme e.g. on Vista using the Aero theme, the dictionary is called Aero.NormalColor.xaml, on XP using the default theme it is Luna.NormalColor.xaml. If the style is not found in the theme dictionary, it looks in Generic.xaml i.e for controls whose look doesn't depend on the theme.
This only applies to any custom controls you have defined i.e. classes derived from Control, directly or indirectly. You can change the default style for a standard control by deriving from it and calling DefaultStyleKeyProperty.OverrideMetadata in the static constructor, but you then have to supply the full style including ControlTemplate.
Note that you can tell WPF to look in an external assembly for your default style by using the ThemeInfo attribute. The external assembly must be named <YourAssembly>.<ThemeName>.dll e.g. PresententationFramework.Aero.dll.
For a generic.xaml file (case insensitive) to be something special, two conditions must be met:
It must be in the Themes sub-root folder in the project
The assembly must be marked with the ThemeInfoAttribute (usually in AssemblyInfo.cs)
Then it serves as the default lookup location for any default styles you wish to apply to your Controls. Note also that for a style to be the default it must declare both its TargetType and x:Key as the Type of Control which is to be styled.
If you wish to add entire themes and theme switching to your application, that is accomplished with some coding, this technique merely defines the default resource dictionary.

Resources