Derived classes and theme inheritance in WPF? - wpf

I'm building a WPF application, and I derived a bunch of controls from the standard WPF control types -- textblocks, buttons, etc. I tried adding a resource dictionary to app.xaml to set the theme, but my custom controls don't seem to be respecting it. (For example, standard Buttons take the Aero theme just fine, but a myButton derived from a Button is still lookless.) Is there a way I can set the theme for my derived controls to be the same as for the base controls?
EDIT: I should note that these custom controls are instantiated at runtime, so I can't manipulate their properties directly via XAML. I can change particular properties like background color by using a Setter in the application resource dictionary, but haven't found a way to set a theme using that technique.

If you have this style in a Resource Dictionary called Dictionary1.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="MyButtonStyle"
TargetType="{x:Type Button}"
BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Width" Value="75" />
<Setter Property="Height" Value="23" />
</Style>
</ResourceDictionary>
Then you can set it on any button with this code behind
Uri resourceLocater = new Uri("/YourAssemblyName;component/Dictionary1.xaml", System.UriKind.Relative);
ResourceDictionary resourceDictionary = (ResourceDictionary)Application.LoadComponent(resourceLocater);
Style myButtonStyle = resourceDictionary["MyButtonStyle"] as Style;
Button button = new Button();
button.Style = myButtonStyle;

Related

Custom control not inheriting parent's styles

I'm trying to maintain a uniform look and feel across elements in my WPF application, and at the same time I want to create a modified TextBox. However, when I do this, styles that I define at the application level for TextBox aren't being applied to the class I created, even though the style created for my custom control is using the BasedOn property.
Is there something I'm missing that's causing this to behave differently than I expect?
I reproduced the issue in a brand-new WPF project in VS2010 with this setup:
C# Code:
public class CustomTextBox : TextBox
{
static CustomTextBox() {
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomTextBox), new FrameworkPropertyMetadata(typeof(CustomTextBox)));
}
}
XAML in Themes\Generic.xaml:
<Style TargetType="{x:Type local:CustomTextBox}" BasedOn="{StaticResource {x:Type TextBox}}"/>
XAML in App.xaml:
<Application.Resources>
<Style TargetType="TextBox">
<Setter Property="Background" Value="Red"/>
</Style>
</Application.Resources>
However, in the designer and when I run the app, the CustomTextBox falls back onthe default styling for the text box instead of having a red background, even though the documentation for the BasedOn property suggests that my derived class should have this styling...
There are several ways that styles in WPF can be extended or inherited. Styles can be based on other styles through this property. When you use this property, the new style will inherit the values of the original style that are not explicitly redefined in the new style.
...
Note: If you create a style with a TargetType property and base it on another style that also defines a TargetType property, the target type of the derived style must be the same as or be derived from the type of the base style.
Short Answer: Your style is based on a StaticResource
<Style TargetType="{x:Type local:CustomTextBox}" BasedOn="{StaticResource {x:Type TextBox}}"/>
When you did this, you are not changing the StaticResource
<Style TargetType="TextBox">
<Setter Property="Background" Value="Red"/>
</Style>
So CustomTextBox is not supposed to inherit the red background.

WPF Apply default style to custom control

I have created a custom combo box control which inherits from Combobox class. There is a type style defined for ComboxBox type on ResourceDictionary which applied automatically for all combo boxes but this is not getting applied the custom control.
Style defined on App.xaml
<Application.Resources>
<Style x:Key="{x:Type ComboBox}" TargetType="{x:Type ComboBox}">
<Setter Property="Background" Value="Gray"/>
</Style>
</Application.Resources>
Custom ComboBox
public class AutoComboBox : ComboBox
MainWindow.xaml
<StackPanel Orientation="Vertical">
<ComboBox Width="200"/>
<local:AutoComboBox Width="200"/>
</StackPanel>
The first combo box will have Background as Gray color as the style defined on App.xaml is applied. But the second combo box still show the default background color.
Is there any way we can apply the same type style on custom control without creating duplicate style for custom control?
Are you using a Theme approach?
If so you should have a ../Themes/Generic.xaml which is your ResourceDictionary.
Your ResourceDictionary should have a <Style> in it with the TargetType="{x:Type local:YourControl}" set for your style.
Furthermore, you should check that in your AssemblyInfo.cs file that ResourceDictionaryLocation.SourceAssembly is set for each of your themes.

What is the most economical way to implement your own window border and title bar?

I am pretty new to WPF and am sitting here with my book trying to figure out the best approach to this application.
The title bar is not part of the client area so I am making my own title bar.
Which way would it be easiest to make this into some sort of resource to apply to all new windows I create?
<Application.Resources>
<Style x:Key="WindowTheme">
<Setter Property="Window.WindowStyle" Value="None"/>
</Style>
<!--Would I create a user control here for the title bar/border and title bar buttons? Or would it be a style?-->
</Application.Resources>
In WPF, there are two ways to use styles: Named styles and typed styles. A named style has an x:Key="..." attribute. A typed style doesn't have a name, but a TargetType="..." attribute (Rem: Named styles can and very often do have a TargetType as well, so named styles and unnamed styles would be more precise). Typed styles automatically get applied to all controls in the scope, which are of type TargetType (not a derived type).
<Style TargetType="{x:Type Window}">
<Setter Property="Background" Value="Blue" />
</Style>
To create your own window, you can set it's template property to a UserControl in the style:
<Style TargetType="{x:Type Window}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The professional way to implement the control template is to implement it 'from scratch', this means not using a UserControl which derives from Window. To do this, you define the visual tree of the Window, and use the WPF feature TemplateParts to define what part of your control template is responsible for what functionality of the window.
Here is a tutorial which describes pretty exactly what you want to do:
CodeProject tutorial

Override Overridden WPF Theme

I am writing a WPF application on WinXP and I have overridden the default theme with the vista theme like this:
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var themerd = new ResourceDictionary();
themerd.Source = new Uri(#"PresentationFramework.Aero;V3.0.0.0;31bf3856ad364e35;component\themes/aero.normalcolor.xaml", UriKind.Relative);
Resources.MergedDictionaries.Add(themerd);
}
And it works fine mostly. When I use control such as a button:
<Button />
The style looks fine, but if I use a Button with a different style like this:
<Button>
<Button.Style>
<Style TargetType="Button">
<Setter Property="Width" Value="80" />
</Style>
</Button.Style>
</Button>
The style will override the specified theme style with the standard WinXP style instead of building on top of it. This is extremely limiting for me. Is there a way to avoid this issue?
Why this is happening
The default BasedOn= for a style is generated using only the current theme's resource dictionary. The technique you show for overriding a theme doesn't actually change the theme dictionary in use: It simply adds the resources from the theme's resource dictionary to the application's resource dictionary. Since the current theme is unchanged, the default BasedOn is also unchanged.
How to solve it
Option 1: Locally override the theme by intercepting calls to uxtheme.dll!GetCurrentThemeName at the Win32 level. This is quite complex but works for all your styles with no changes to your XAML.
Option 2: Set BasedOn using a custom MarkupExtension. It would look like this:
<Style TargetType="Button" BasedOn="{DefaultAeroStyle Button}"> ...
Your custom MarkupExtension would load the Aero theme dictionary on first use and store it in a static field. Its constructor would take a Type, and its ProvideValue would look up the type in the dictionary to find the style.
Option 3: Set BasedOn to an intermediate named style. It would look like this:
<Application ...>
<Application.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="... theme path ..." />
</ResourceDictionary.MergedDictionaries>
<Style x:Key="ThemeButtonStyle" TargetType="Button" BasedOn="{StaticResource {x:Type Button}}" />
<Style x:Key="ThemeListBoxStyle" TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}" />
...
</ResourceDictionary>
</Application.Resources>
</Application>
Now in your lower-level dictionary you can say:
<Style TargetType="Button" BasedOn="{StaticResource ThemeButtonStyle}" />
Option 4: Set BasedOn using a static property and the x:Static markup extension

WPF: How do I inherit property values to all child controls?

I have UserControls containing other controls. I want that if I set a Foreground color for the UserControl, all child controls automatically inherit it. I have the same problem with font style/size.
Can I set these properties somehow to auto/inherit? Is this possible to set all subcontrols without a loop?
You can you create resource dictionaries to define default styles globally.
You can also reference a resource dictionary or define a style in any object.
In either case those styles will apply to all child objects that don't have a style explicitly defined...
Example:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<!--Default styles that will apply to any object of the specified type (if it doesn't have style set locally)-->
<Style TargetType="Label" >
<Setter Property="FontWeight" Value="Bold"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Padding" Value="0"/>
</Style>
</ResourceDictionary>
Look into using Styles and BasedOn settings.
I recently wrote an example of something similar located here. Unfortunally the question was related to Silver Lite so didn't answer the question, but I think it may give you some ideas on where to look.

Resources