How do I create a Style within a WPF UserControl? - wpf

I want to set the style of some controls on my UserControl, but can't seem to find the right syntax:
<UserControl x:Class="HiideSRM.WIDSModule.BiometricStatusIndicator"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
<Style TargetType="{x:Type Border}">
<Setter Property="Width" Value="10"/>
</Style>
<StackPanel Orientation="Horizontal" x:Name="Panel">
<Border Height="50" Margin="1"/>
<Border Height="10" Margin="1"/>
<Border Height="10" Margin="1"/>
<Border Height="10" Margin="1"/>
</StackPanel>
</UserControl>

first, place your styles into a .Resources tag--which can be the child of pretty much any control tag (eg. border, usercontrol, grid, etc.)
second, you can specify the style in the tag, but since you didnt declare an x:key on your resource, the style will apply to ALL borders in this control.
<UserControl.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="Width" Value="10"/>
</Style>
</UserControl.Resources>
note that the syntax is different for silverlight. instead of TargetType="{x:Type Border}" you would use TargetType="Border"

Related

Apply base style of window to inherited window

I have defined a style for the Window class in my ResourceDictionary:
<Style x:Key="windowStyle"
TargetType="{x:Type Window}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Border Width="300" Height="300" BorderBrush="Red" BorderThickness="3">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Now I want a specialized window. To this end I inherit a new class from Window and add custom DependecyProperties etc.
My goal is to reuse the base style, ie. I pretty much only want to fill the ContentPresenter from the base style with a grid and add a new ContentPresenter in one of its cells, so I tried this:
<Style x:Key="customWindowStyle"
BasedOn="{StaticResource windowStyle}"
TargetType="{x:Type local:CustomWindow}">
<Setter Property="ContentTemplate">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:CustomWindow}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="{TemplateBinding Source}" />
<ContentPresenter Grid.Column="1" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Which gives me an exception at runtime, since the ContentTemplate is of type DataTemplate as opposed to ControlTemplate. Of course if I Set the Template instead of ContentTemplate in the customWindowStyle, I lose the style of the base window.
Is there another way to achieve this goal?

WPF write ControlTemplate for a ContentControl when its content type is UserControl

I have a ContentControl like this:
<ContentControl>
<userControls:TestControl/>
</ContentControl>
OR like this [when i have PRISM system]:
<ContentControl prism:RegionManager.RegionName="TestView"/>
I see the final UserControl well until this step when i start the program.
In the above samples the Content type is UserControl. Now i want give a ControlTemplate to this ContentControl. Then i created a style named StyleTest and used it in my Xaml:
<ContentControl Style="{StaticResource StyleTest}"> .....
My style:
<Style x:Key="StyleTest" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Grid Margin="10">
<Border CornerRadius="10" BorderBrush="#ffffffff" BorderThickness="5">
<StackPanel>
<ContentPresenter Content="{Binding}"/>
<TextBlock>Some additional text to test template</TextBlock>
</StackPanel>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
But when i start the program the UserControl can not be seen and i just see this text and a border around it: Some additional text to test template
What i must write instead of above line of code to see my UserControl again with a white border around it?
Why the UserControl not showing with above code (above style)?
There are 3 ways to do this.
- by setting the ContentTemplate
- by setting the Template
- or using the Border directly and apply a style.
In this case I would use the Border and apply a style because it looks like the ContentControl is only used to do add a styled Border.
<StackPanel>
<StackPanel.Resources>
<Style x:Key="BorderStyle" TargetType="{x:Type Border}">
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BorderThickness" Value="5" />
<Setter Property="CornerRadius" Value="10" />
<Setter Property="Margin" Value="10" />
</Style>
<Style x:Key="ContentTemplateStyle" TargetType="{x:Type ContentControl}">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate>
<Border Style="{StaticResource BorderStyle}">
<!-- Bind to the DataContext of the DataTemplate which is the Content of the ContentControl -->
<!-- <ContentPresenter Content="{Binding}" />-->
<!-- TemplateBinding improves performance -->
<ContentPresenter Content="{TemplateBinding Content}" />
<!-- Using the TemplatedParent -->
<!--<ContentPresenter Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"/>-->
</Border>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ControlTemplateStyle" TargetType="{x:Type ContentControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ContentControl">
<Border Style="{StaticResource BorderStyle}">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Resources>
<ContentControl Style="{StaticResource ContentTemplateStyle}">
<Button>ContentTemplateStyle</Button>
</ContentControl>
<ContentControl Style="{StaticResource ControlTemplateStyle}">
<Button>ControlTemplateStyle</Button>
</ContentControl>
<Border Style="{StaticResource BorderStyle}">
<Button>BorderStyle</Button>
</Border>
</StackPanel>
datacontext is a type?. Normally it will be inherited in the visual tree so I think it should be left blank.
Content is the content of the parent. Normally you can use a template binding or set the content source property.
but using this template will only show you a white border around content. The original template is lost. So you should provide the entire template for the control.
Now maybe the control contains margin and border properties and you can set those from your style and leave the original template in place.
I found my mistake place and changed this part of my codes:
<Style x:Key="StyleTest" TargetType="ContentControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
To this one:
<Style x:Key="StyleTest" TargetType="ContentControl">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate >
When i play with Template its effects is on inner content of the ContentControl (in this question: template of the UserControl) But when i play with ContentTemplate, its effects is on ContentControl layout.
ContentPresenter tag is same and it works now...
<ContentPresenter Content="{Binding}"/>

WPF Style Sheets and Bindings

I have a style sheet that i want to be used on different custom controls.
Example
Stylesheet.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style x:Key="ExampleProgressBar" TargetType="ProgressBar">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ProgressBar">
<Border DataContext="{Binding RelativeSource={RelativeSource Self}}" Background="{Binding Path=Example_BG}">
<Grid x:Name="PART_Track" >
<Rectangle x:Name="PART_Indicator" HorizontalAlignment="Left" Fill="#FF1B9AF1" RadiusX="5" RadiusY="5"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
When I use something like above on the style sheet it doesn't bind to the custom control....
Is there anyway to bind stylesheet styles to work with many custom controls?

How to change templatized controls using styles

I'm using a ControlTemplate for defining the appearance of my buttons in a WPF application. Additionally I would like to use styles to set certain aspects of my buttons. These styles should set properties on elements defined in the ControlTemplate, like (simplified):
<Window.Resources>
<ControlTemplate x:Key="Template1" TargetType="Button">
<Grid>
<Rectangle Name="rect" Fill="White" Stroke="Blue" StrokeThickness="2"/>
<TextBlock Name="text" Text="Hallo" Foreground="Red" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
<Style x:Key="Style1" TargetType="Button" >
<Setter TargetName="rect" Property="Fill" Value="Red"/>
</Style>
</Window.Resources>
Now the compiler complains that the TargetName "rect" isn't a valid target which I can understand since an untemplatized Button doesn't contain an element named "rect".
I know that I could change the style to setting the complete template, but I would like to avoid that (because the template is much more complex than shown here and I do not want to duplicate it for each style...)
Is it possible to achieve this behaviour? Perhaps by setting the TargetType right? Any other ideas?
You can NOT override only part of the control template. You can either change everything or nothing.
You can have setters for properties on the style though.
The standard pattern is to use TemplateBinding in the control template to bind to properties of the control itself, and then set the properties on the control in the style. For example:
<Window.Resources>
<ControlTemplate x:Key="Template1" TargetType="Button">
<Grid>
<Rectangle Name="rect" Fill="{TemplateBinding Background}" Stroke="Blue" StrokeThickness="2"/>
<TextBlock Name="text" Text="Hallo" Foreground="Red" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
<Style x:Key="Style1" TargetType="Button" >
<Setter Property="Background" Value="Red"/>
</Style>
</Window.Resources>
This will bind the Fill property on rect to the Background property on the Button. The style will set the Background property to Red, which will cause the Fill to be set to Red.
In order to set defaults, you would normally create a style that set the template as well as the other properties:
<Window.Resources>
<Style x:Key="BaseStyle" TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Grid>
<Rectangle Name="rect" Fill="{TemplateBinding Background}" Stroke="Blue" StrokeThickness="2"/>
<TextBlock Name="text" Text="Hallo" Foreground="Red" VerticalAlignment="Center" HorizontalAlignment="Center"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="Background" Value="White"/>
</Style>
<Style x:Key="Style1" TargetType="Button" BasedOn="{StaticResource BaseStyle}">
<Setter Property="Background" Value="Red"/>
</Style>
</Window.Resources>
The first style will apply the template and set Background to White, so the rectangle will be white. The second style inherits from the first one but sets the Background to Red, so the rectangle will be red.

WPF/XAML Custom ScrollViewer ScrollBar w/o Custom ScrollBar in Inner Controls (like TextBox)

and thank you for looking into my question. I would like to customize the ScrollBar in my ScrollViewer. No problem. But wait. When I do that, it also changes the ScrollBar of the inner controls. I don't want to impact those ScrollBars. How do I specify the correct scope?
Here's the XAML that almost works:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ScrollViewer>
<ScrollViewer.Resources>
<Style TargetType="{x:Type ScrollBar}">
<Setter Property="Background" Value="Red" />
</Style>
</ScrollViewer.Resources>
<TextBox Height="200" Width="200" VerticalScrollBarVisibility="Visible" />
</ScrollViewer>
</Page>
Because ScrollViewer supports only one child object I added a Grid to wrap the textbox.
In my case I applied an override style to make the text box blue.
If you remove the entire setter from the Grid you get the default.
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<ScrollViewer>
<ScrollViewer.Resources>
<Style TargetType="{x:Type ScrollBar}">
<Setter Property="Background" Value="Red" />
</Style>
</ScrollViewer.Resources>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type ScrollBar}">
<!-- remove setter to get default -->
<Setter Property="Background" Value="Blue" />
</Style>
</Grid.Resources>
<TextBox Height="200" Width="200" VerticalScrollBarVisibility="Visible" />
</Grid>
</ScrollViewer>
</Grid>
</Page>

Resources