Apply different styles depending on user theme - wpf

I have a WPF application in which I change the default styles a bit, to add some common padding or margin, or something like that. I usually do that either in the Window.Resources or in some resource dictionary I either load in the window’s or application’s resources. An example style could be this:
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="5" />
</Style>
So far so good. Note though that I am changing a default component, not a user component.
Today I noticed that the Aero2 theme that is used in Windows 8 comes with a few different standard styles than I am used to from Windows 7’s Aero theme. Unfortunately I was not really able to make a generic style that would just work in both.
So, I want to be able to specify different styles, depending on which theme the user is using. For example, if the user is using Aero, I want to load Aero-styles.xaml, and if it’s Aero2 on Windows 8, I want to load Aero2-styles.xaml instead.
I was hoping this would be possible by using the Themes directory and providing Aero.NormalColor.xaml and Aero2.NormalColor.xaml. Unfortunately that seems to only work for custom controls, but not the built-in controls. It also does not make the available keys available to be used as a static/dynamic reference.
Is there a way to do this? To provide maybe a base resource dictionary that contains customizations and then another theme-dependent dictionary with minor adjustments to the used theme?

Detect theme on startup (before any UI is loaded), and dynamically add appropriate ResourceDictionary to Application.Resources.MergedDictionaries.
This worked for me.

Related

Need advice on how to change colors

I'm building a WPF application that will be run on laptop computers mounted in police cars. The app has to have a "Night Mode" which will use darker colors to be less of a strain on the eyes at night.
Since the application is going to be used while the officer is driving, I've increased the size of all of the controls and I've defined new default templates for things like comboboxes. This is to make the screen easier to read at a glance and to make it easier to hit controls on the touch screen when you have sausage fingers, like I do.
I've created an enumeration called TimesOfDay. There are two values in the enumeration, DayTime and NightTime. Each control has a DepenencyProperty called TimeOfDay of the TimesOfDay enumeration type. There's a button on the main screen that you push to change the value of the TimeOfDay property. When you click the button, it cycles the TimeOfDay property's value between the two values.
I'm still pretty new to WPF, so I'm not sure how to go about this, on the Xaml side. I think what I need to do is create two named styles, for example one called DayStyle and another called NightStyle. Then I need to add triggers somewhere to change the style applied to the controls when the TimeOfDay property changes. Is that right?
Do I just change the background and foreground colors of the controls by type? Can I do it by element name?
I'm very fuzzy on all of this. Any help would be appreciated.
Tony
Each control has a DepenencyProperty called TimeOfDay of the TimesDay enumeration type.
Don't do that, just create two complete themes in separate ResourceDictionaries which you then can switch via the MergedDictionaries in the Application.Resources. There is no need to put the day-time information on the controls.
Follow this guide: http://weblogs.asp.net/psheriff/archive/2009/12/01/load-resource-dictionaries-at-runtime-in-wpf.aspx
Create various xaml resource files, but make sure the file does not compile and copies into the bin directory instead.
Decorate your xaml controls with DynamicResources.
Load in your resources through code.
Basically, you are looking to "skin" your application. The code that loads in your resource file can take advantage of the TimeOfDay enumeration.
If you want it automated you can even have some static class that has a timer to automatically attempt to change the resource and set the timer on the application startup. :)
I wouldn't duplicate the style, because I hate duplicated code... You could easily achieve that with a trigger in the ControlTemplate:
<Trigger Property="TimeOfDay" Value="NightTime">
<Setter TargetName="someControl" Property="Background" Value="Black" />
<Setter TargetName="someOtherControl" Property="ForeGround" Value="Yellow" />
...
</Trigger>
Another option is to use the technique I described here. This way you don't even need to put the TimeOfDay information on the control itself, it can be an ambient property.

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);

App-wide Font resources in Silverlight

I'm looking to see if it is possible to use app-wide font in Silverlight controls that can be set in a application.resources and then used throughout the app. They don't need to specifify the other things about a font like bold or italic, just the name.
Mostly, this is for custom fonts that would require to be embedded into the app. For example, I'm looking for something simple like (not of any particular control or control type)...
<Setter x:Key="My First Font"
Property="FontFamily"
Value="VINERTIC.TTF#Viner Hand ITC" />
Then in any given control I would type...
<TextBlock FontFamily="{StaticResource "My First Font"}"
x:Name="ApplicationTitle"
Text="NEXT PAGE" Foreground="Red"/>
...or...
FontFamily="{Binding "My First Font"}"
or some such thing.
I know what I did doesn't work, but that is the desired effect.
I can't seem to find any documention on how to set app-wide font families. Any advice?
Here is some information I think will get you started.
First off, the easiest way I know to embed a font in a shared library (ex: a Silverlight Class library), is to do the following:
Have a class library, and know its default namespace. For this example, the default namespace of the class library is Common.Windows.
Have a font. For this example, Action Man Bold.ttf, which contains the named font Action Man.
Add the font somewhere in the shared library project. For example, the Assets/Fonts folder.
Set the build action on the file to Resource.
Build the project.
After following these steps, you can refer to the font wherever you please, including styles, with syntax similar to the text block below:
<TextBlock
FontFamily="/Common.Windows;component/Assets/Fonts/Action Man Bold.ttf#Action Man" />
Note that the FontFamily expression above worked within the container project and within a referencing project. I didn't test this process with a zip archive of fonts, but I'd bet a fancy rock out of the garden that it would still work.
That should get you started. If you are interested in going the extra (and useful) step of declaring the font in a style, and using the style on your controls, consider taking a look at this resource:
http://www.silverlight.net/learn/quickstarts/control-styles/

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

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.

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