Wpf CustomControl why is the style setting not overiding the default - wpf

Consider the following really simple CustomControl:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ViewToLearn.WpfControls">
<Style TargetType="{x:Type local:VtlCustomButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:VtlCustomButton}">
<Grid>
<Button Content="Hi" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
And if I add a couple of these to a test project I get the following:
So far so good. Now I decide that in fact I'd prefer to set the background colour of each button to be red. Obviously I could set each button's background property individually;
<Button Content="Hi" Background="Red" />
And that will work. Logic dictates however that if I want all buttons to have a red border then clearly a style would make more sense, so to that end I alter the code of the control like so:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ViewToLearn.WpfControls">
<Style TargetType="{x:Type Button}">
<Setter Property="Background"
Value="Red" />
</Style>
<Style TargetType="{x:Type local:VtlCustomButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:VtlCustomButton}">
<Grid>
<Button Content="Hi" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
However this is having no effect. I'm sure that the principle is correct but applying it to the specifics of a custom control is constantly frustrating me. Why is this as it currently is failing to produce the expected result. Is it because of where I put the style, or something more fundamental that I have failed to grasp?
Edit
I've been trying to get to grips with creating Custom (NOT user) controls and the way to apply styles and templates to them. The control I really want to influence is made up of several different element (buttons, images, panels textboxes etc) but for the sake of this question I opted for a a custom control based on the standard vs template resulting in the code shown above. Using based on definitely hasn't appeared to work, but I did find that the following amendment did work. I'd love to know why this works over my original and what I'm really doing incorrectly in the first place (ie there's probably a more efficient way to go about this especially as there are several elements whose style I'd like to amend).
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ViewToLearn.WpfControls">
<Style x:Key="vtlstyle"
TargetType="{x:Type Button}">
<Setter Property="Background"
Value="Red" />
</Style>
<Style TargetType="{x:Type local:VtlCustomButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:VtlCustomButton}">
<Grid>
<Button Content="Hi"
Style="{StaticResource vtlstyle}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Use BasedOn:
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="Red" />
</Style>
<Style x:Key="myButtonStyle" TargetType="{x:Type local:VtlCustomButton}" BasedOn="{StaticResource {x:Type Button}}">
<Setter Property="Content" Value="Hi"/>
</Style>
EDIT>>>>>
Using the style on a button(out of resources):
<local:VtlCustomButton Style="{StaticResource myButtonStyle}" />

Related

How to set a control resource dictionary in a Style in XAML?

I have a UI in Silverlight with some borders, and with a TextBlock inside that borders. There will be other TextBlocks outside borders.
<Border>
<TextBlock>This text should be centered</TextBlock>
</Border>
<Border>
<TextBlock>This one too</TextBlock>
</Border>
<TextBlock>this one shouldn't</TextBlock>
What I'm trying to achieve is to format all TextBlock's inside a Border, without having to set the style in every TextBlock. If it was CSS , it will be something like that : .border .textBlock { (...) }
I know i can set a style inside the scope of a border:
<Border>
<Border.Resources>
<Style TargetType="TextBlock" BasedOn="{StaticResource DefaultTextBlockStyle}">
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
</Style>
</Border.Resources>
<TextBlock>Centered Text</TextBlock>
</Border>
But I would still need to set this to every border in my page. So now i presente the question, can i set in a style, in order to set it one time to affect all Borders? I tried the code bellow, but it didn't work. It didn't give me any errors, but it didn't affect the TextBlock formatting either.
<Style TargetType="Border">
<Setter Property="Resources">
<Setter.Value>
<ResourceDictionary>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</ResourceDictionary>
</Setter.Value>
</Setter>
</Style>
Try this:
<Style TargetType="Border">
<Style.Resources>
<Style TargetType="TextBlock">
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
</Style.Resources>
</Style>
This works in WPF. In Silverlight I am afraid you cannot do this though.

Setting RenderTransform in a nested style

I'm using .Net 3.5 on Windows 8, with the default Aero theme.
This was supposed to be an answer to Scale Checkbox without scaling content but it didn't work as easily as I expected. I'm trying to:
scale the box in a checkbox control
in a style, so I can apply the change to all checkboxes (or only some)
independently of its text, with no need to compensate.
I have a UserControl with this Resources:
<UserControl.Resources>
<ResourceDictionary>
<!-- ... -->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Resources/CheckBoxStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
Resources/CheckBoxStyle.xaml is this:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework">
<Style TargetType="{x:Type CheckBox}">
<Style.Resources>
<Style TargetType="{x:Type BulletDecorator}">
<Setter Property="RenderTransform">
<Setter.Value>
<ScaleTransform ScaleX="2" ScaleY="2"/>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
</Style>
</ResourceDictionary>
The primitives namespace is in case whatever I settle on needs to know what BulletDecorator is.
I found BulletDecorator in the Aero theme for .Net 3.5 from here, behind the "Default WPF Themes" link, per this answer.
I'm seeing no difference in the size of my checkbox boxes. I don't think I grabbed the wrong element type from the theme, but what else could be happening?
Edit 1:
BulletDecorator contains the checkbox's content anyway, so I tried dropping requirement #3. Now I have a huge box and huge text, and want to shrink the text back down. Here is CheckBoxStyle.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework">
<Style TargetType="{x:Type CheckBox}">
<Style.Resources>
<Style TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContentControl}">
<ContentPresenter>
<ContentPresenter.LayoutTransform>
<ScaleTransform ScaleX="0.5" ScaleY="0.5" />
</ContentPresenter.LayoutTransform>
</ContentPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform ScaleX="2" ScaleY="2"/>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
I found a solution, although it's not perfect. A better answer would still be accepted.
I used Snoopto determine that the element I'm concerned with is already a ContentPresenter. It contains a TextBlock, but for some reason that can't be styled (and it's shown in parentheses in Snoop's hierarchy). Here's my resulting CheckBoxStyle.xaml:
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:primitives="clr-namespace:System.Windows.Controls.Primitives;assembly=PresentationFramework">
<Style TargetType="{x:Type CheckBox}">
<Style.Resources>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform ScaleX="0.5" ScaleY="0.5" />
</Setter.Value>
</Setter>
</Style>
</Style.Resources>
<Setter Property="LayoutTransform">
<Setter.Value>
<ScaleTransform ScaleX="2" ScaleY="2"/>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>

Accessing elements parent style XAML Silverlight

For example, i have the following Style:
<Style x:Key="MyStyle" TargetType="MyType">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MyType">
<Grid>
<Button x:Name="MyButton"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Is it possible to inherit from him a different style and change the properties of the button "MyButton"? For example change the property Visibility?
Thank You!
There are more than one way of achieving this.
Use BasedOn
<Style TargetType="MyChildType" BasedOn="{StaticResource MyStyle}" >
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="MyType">
<Grid>
<Button x:Name="MyButton" Visibility="Collapsed"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
Apply style to MyButton and put Trigger in Style.Triggers to change the properties of button depending on the properties of parent

What does a Property Setter correspond to when used in conjunction with ControlTemplates?

I have the following Style (stripped for brevity) and have some questions based on it. To my understanding, if a ControlTemplate replaces the entire visual tree of a control for which the Style is based on, what effect do the property Setters have then?
In this example, don't the property Setters for FontSize, Margin, Height etc. correspond to the respective properties on the CheckBox itself? If you replace the Template property of a control, what will these Setters then correspond to if the CheckBox is no longer rendering it's default appearance?
<Style x:Key="KeyName" TargetType="CheckBox">
<Setter Property="FontSize" Value="11" />
<Setter Property="Margin" Value="0 0 1 0" />
<Setter Property="VerticalAlignment" Value="Top" />
<Setter Property="Height" Value="18" />
... common property setters etc.
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="CheckBox">
<Border>
<StackPanel>
<Ellipse Name="Ellipse" Width="7" Height="7" />
<ContentPresenter Content="{TemplateBinding Content}" />
</StackPanel>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.Setters>
<Setter Property="Foreground" Value="WhiteSmoke" />
</Trigger.Setters>
</Trigger>
... custom triggers etc ...
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
They are a way to provide an initial default value for properties on the object that's being styled, they don't auto force anything on the Template for you. They can however be used in the control template.
Values that are set using the setters in a style can be overridden by local values in the xaml. for example.
This xaml file draws a single label that has had it's style altered to include a grid that takes on the background color, I've defaulted the color to red in the setter and it appears as red.
<Window x:Class="ContextMenu.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type Label}">
<Setter Property="Background" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Grid Background="{TemplateBinding Background}">
<TextBlock Text="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Label>Test</Label>
</Window>
if I was to change the label line to blue on the instance of the label, you can see this overrides the setter.
<Window x:Class="ContextMenu.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<Style TargetType="{x:Type Label}">
<Setter Property="Background" Value="Red"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Label}">
<Grid Background="{TemplateBinding Background}">
<TextBlock Text="{TemplateBinding Content}"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<Label Background="Blue">Test</Label>
</Window>

Applying a style to all derived classes in WPF

I want to apply a style to all classes derived from Control. Is this possible with WPF?
The following example does not work. I want the Label, TextBox and Button to have a Margin of 4.
<Window x:Class="WeatherInfo.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Wetterbericht" Height="300" Width="300">
<Window.Resources>
<Style TargetType="Control">
<Setter Property="Margin" Value="4"/>
</Style>
</Window.Resources>
<Grid>
<StackPanel Margin="4" HorizontalAlignment="Left">
<Label>Zipcode</Label>
<TextBox Name="Zipcode"></TextBox>
<Button>get weather info</Button>
</StackPanel>
</Grid>
</Window>
Here's one solution:
<Window.Resources>
<Style TargetType="Control" x:Key="BaseStyle">
<Setter Property="Margin" Value="4"/>
</Style>
<Style BasedOn="{StaticResource BaseStyle}" TargetType="Button" />
<Style BasedOn="{StaticResource BaseStyle}" TargetType="Label" />
<Style BasedOn="{StaticResource BaseStyle}" TargetType="TextBox" />
</Window.Resources>
<Grid>
<StackPanel Margin="4" HorizontalAlignment="Left">
<Label>Zipcode</Label>
<TextBox Name="Zipcode"></TextBox>
<Button>get weather info</Button>
</StackPanel>
</Grid>
This is not possible in WPF. You have a couple of options to help you out:
Create one style based on another by using the BasedOn attribute.
Move the common information (margin, in this case) into a resource and reference that resource from each style you create.
Example of 1
<Style TargetType="Control">
<Setter Property="Margin" Value="4"/>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type Control}}">
</Style>
Example of 2
<Thickness x:Key="MarginSize">4</Thickness>
<Style TargetType="TextBox">
<Setter Property="Margin" Value="{StaticResource MarginSize}"/>
</Style>

Resources