How to work with control inheritance - c#

I use Telerik as a WPF library. We can apply a theme on Telerik controls using application Theme (i.e. theme manager). For Microsoft controls we can set a property to make the theme apply.
The problem is : I don't want to write this line :
<Style TargetType="{x:Type CheckBox}">
<Setter Property="telerik:StyleManager.Theme" Value="{Binding Source={StaticResource Settings}, Path=Default.Theme}" />
</Style>
for every type: CheckBox, TextBlock, TextBox etc.. for maintenance purpose.
If I target <Style TargetType="{x:Type Control}"> inheritance doesn't work well.
Base class of CheckBox is Control but when I set property on every control it doesn't set property on every child of control too. Any idea how i can do this?

Related

WPF ContextMenu and MenuItem Cannot set OverridesDefaultStyle property in the default Style WPF

I'm trying to create library with components that have an extended appearance configuration.
Instead of creating more styles and templates, I can inherit style from default style for custom component, and override few values.
I created CustomizableContextMenu and CustomizableMenuItem classes inherited from default ContextMenu and MenuItem and extended them by additional constructor. For example for CustomizableContextMenu.
static CustomizableContextMenu()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(CustomizableContextMenu),
new FrameworkPropertyMetadata(typeof(CustomizableContextMenu)));
}
Styles and templates are in separate files that are referenced in the file "Themes/Generic.xaml".
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/FluentControls;component/Themes/CustomizableContextMenuStyle.xaml"/>
<ResourceDictionary Source="pack://application:,,,/FluentControls;component/Themes/CustomizableMenuItemStyle.xaml"/>
</ResourceDictionary.MergedDictionaries>
<Style BasedOn="{StaticResource CustomizableContextMenuStyle}" TargetType="{x:Type components:CustomizableContextMenu}"/>
<Style BasedOn="{StaticResource CustomizableMenuItemStyle}" TargetType="{x:Type components:CustomizableMenuItem}"/>
Until I try to make style and template in the same app (without overriding DefaultStyleKeyProperty) and making reference to style in MainWindow.xaml everything works fine. But now (except other components such Button, TextBox, ComboBox, CheckBox, etc.) I have a problem with it.
I'm trying to create CustomizableButton (the same problem appears when I'm using standard Button) with CustomizableContextMenu and CustomizableMenuItem, but it didn't work. The message I've got from the IDE was "Cannot set OverridesDefaultStyle property in the default Style"
This is implementation code of CustomizableContextMenu.
<Components:CustomizableButton
...
Content="I have ContextMenu!">
<Button.ContextMenu>
<Components:CustomizableContextMenu
Background="#C0000000"
BorderBrush="#C00078D7"
BorderThickness="1"
Foreground="White">
<Components:CustomizableMenuItem
Background="#C0000000"
BorderBrush="#C00078D7"
Foreground="White"
Header="Item Test 1"
InputGestureText="Ctrl+1"
Margin="0,1"/>
</Components:CustomizableContextMenu>
</Button.ContextMenu>
</Components:CustomizableButton>
It's possible to do it in easy way, or not? And I must remove override of DefaultStyleKeyProperty, and import style in the traditional way to MainWindow.xaml and use it by setting property in component definition?
Remove the following <Setter> from the default style:
<Setter Property="OverridesDefaultStyle" Value="True" />
Since the style in themes/generic.xaml is the default style by defintion, it cannot override another default style.

Change the control property globally in wpf

I have a back button which is copied almost to all the Controls in my application.
I have set the styles and properties of the button on each individual control (usercontrol)
Now I want to change the text property of the button of all the control (usercontrol).
I don't want to go and change the property of each control.
Please help me setting a global property which sets the property in one place.
Since the style is common to all pages. Create the style without a key/name, just the target type would do.
<Style TargetType="{x:Type Button}">
Then do either of the following -
Add it to the App.XAML for visibility throughout the app
Better approach would be to define a resource dictionary file and import it, wherever you need it.
<Style TargetType="{x:Type Button}">
<Setter Property="Text" Value="{Binding text}" />
<Setter Property="...." Value="{Binding ....}"/>
</Style>
Add this to App.xaml file as you want it to be global style for all your user controls.

Apply template to control and children

I've been tinkering around with WPF MDI, which sets the control template for MDI Child objects. So when you add an MdiChild object and set its Content to a UserControl it looks good, but if you inherit from MdiChild then it doesn't work.
The template code looks something like this:
<Style TargetType="{x:Type local:MdiChild}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:MdiChild}">
<!-- ... -->
I'd like this template to apply not just to MdiChild, but also to anything that derives from it. How can I go about this? The only way I can think of is to create a style targeting each derived class that is based on the MdiChild style, but that's not very desirable.
You have to declare style for each derived type but with WPF you have power to inherit from base style using BasedOn.
<Style TargetType="{x:Type local:DerivedMdiChild}"
BasedOn="{StaticResource {x:Type local:MdiChild}}">
......
</Style>
This way all setters, triggers etc. will be inherited and you don't have to redefine them again for each derived style. Moreover, it gives you power to override setter of base style in case you want some different behaviour in derived version.

Inheriting ComboBox in WPF using C#

I am deriving from Combobox to add some additional functionality, such as a checkbox.
The issue is, even with a simple implementation the Items.Add method does not work.
For example, here is the XAML:
<Style TargetType="{x:Type local:CustomControl1}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomControl1}">
<ComboBox>
</ComboBox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The ComboBox is visible, but no information is added when I call the Items.Add method. What do I need to implement from the ComboBox class to achieve this? Do I need to do something with the popup? Add a Textblock?
That doesn't look to me like you're deriving from ComboBox... It looks to me like you're putting a ComboBox inside the ControlTemplate of your custom control.
If you are also deriving your custom control from ComboBox and calling Items.Add on your custom control, then you've basically got two lists of data (one for your custom control and one for the combobox in your controltemplate) and they are not linked in any way.
I'd suggest popping open Expression Blend and taking a look at the control template for a default ComboBox. If you want to derive from ComboBox you can then modify that controltemplate to suit your needs.

WPF Updating styles at runtime

I would like to update the default Window style dynamically at runtime so I can change the FontSize and FontFamily dynamically at runtime. I found that Styles in your resource dictionary are sealed at runtime and cannot be changed, so I used the following method of updating the style:
<Style TargetType="{x:Type Window}">
<Setter Property="FontFamily" Value="Arial"/>
<Setter Property="FontSize" Value="12pt"/>
</Style>
With the following code:
Style newStyle = (Make a copy of the old style but with the FontSize and FontFamily changed)
// Remove and re-add the style to the ResourceDictionary.
this.Resources.Remove(typeof(Window));
this.Resources.Add(typeof(Window), newStyle);
// The style does not update unless you set it on each window.
foreach (Window window in Application.Current.Windows)
{
window.Style = newStyle;
}
There are several problems with this approach and I have a few questions as to why things are the way they are.
Why are styles sealed at runtime and is there a way of making them unsealed?
When I re-add the new style, why is this not picked up by all of my windows? Why do I have to go and manually apply it to every window?
Is there a better way?
I would probably tackle this with a "settings service" which exposes properties for the various settings, and fires INPC as you would for normal binding. Next up I'd change that style to be something like:
<Style x:Key="MyWindowStyle">
<Setter Property="FontFamily" Value="{Binding Path=FontFamily, Source={StaticResource SettingsService}, FallbackValue=Arial}"/>
<Setter Property="FontSize" Value="{Binding Path=FontSize, Source={StaticResource SettingsService}, FallbackValue=12}"/>
</Style>
With your "settings service" defined as a static resource:
<services:SettingsService x:Key="SettingsService"/>
Then in each window make sure the style is set as a DynamicResource:
<Window Style="{DynamicResource MyWindowStyle}" .... >
There is often a lot of misunderstanding around the differences between Static and Dynamic resources, but the basic difference is Static is a "one time" setting whereas Dynamic will update the settings if the resource changes.
Now if you set those properties in your "settings service" they will fire INPC, which will update the Style, which the DynamicResource will pick up on and alter the Window properties accordingly.
Seems like a lot of work, but it gives you some nice flexibility, and all the "heavy lifting" is done purely using Bindings. We use a similar technique on a project I'm working on at the moment so when a user chooses a fill/stroke colour the various tools in the toolbar update to reflect the new values.

Categories