I have created custom control and a default style for it.
My XAML is simple:
<Style TargetType="{x:Type local:MyControl}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border CornerRadius="10" BorderThickness="1" Background="Transparent" BorderBrush="Black"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I connect to this style using DefaultStyleKey:
DefaultStyleKey = typeof(MyControl);
And it works. But now I want to create other style for my control. It's because my control can have some modes defined as enums, like:
public enum ControlMode
{
Mode1,
Mode2
}
Now, when my control is in Mode1 I want it to have its default style. But when it's in Mode2 I want it to have another style, like:
<Style TargetType="{x:Type local:MyControl}" x:Key"styleForMode2>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderThickness="1" Background="White" BorderBrush="Black"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
How can I achieve that? DefaultStyleKey works only for type name, so the only thing I came up with is to create another class for my control: MyControlWithMode2. But I'm sure there is more proper way. Right?
(this is library not an application, so I cannot use application's resources)
Assuming your control has a Mode property, the default Style could declare Triggers to set different ControlTemplates for different modes:
<Style TargetType="local:MyControl">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border CornerRadius="10" BorderThickness="1"
Background="Transparent" BorderBrush="Black"/>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Mode" Value="Mode2">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderThickness="1" Background="White"
BorderBrush="Black"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Related
I'm trying to achieve this through XAML code but to no avail.
I have the following XAML code:
App.xaml
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Path Fill="{TemplateBinding Background}"
Data="M 0,22.5 22.5,0 27.5,5 10,22.5 27.5,40 22.5,45"/>
<Border x:Name="border"
BorderThickness="2"
BorderBrush="Red"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
And use it like so:
<Button Style="{StaticResource ButtonStyle}" Height="100" Width="100"/>
It gives me this but I want the red border to be inside the button.
I tried adding this
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="2"/>
instead of creating a grid but now the border doesn't show.
I guess I could create another path that would act as a border but is there a simpler way?
<Style x:Key="ButtonStyle" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Black"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<Path Fill="{TemplateBinding Background}" Stroke="Red" StrokeThickness="3"
Data="M 0,22.5 22.5,0 27.5,5 10,22.5 27.5,40 22.5,45"/>
<Border x:Name="border"
BorderThickness="2"
BorderBrush="Red"/>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
trying to use Stroke and StrokeThickness properties.
I make use of a resource dictionary with all my styles, icons and more.
Now I'd like to add my own titlebar implementing the title of the solution, my image and a ContentPresenter.
When using the WindowStyle I'd like to add application specific items inside this ContentPresenter, but I don't know how to proceed.
This is my WindowStyle. Inside the Grid you'll find the ContentPresenter I'd like to fill.
<Style TargetType="{x:Type Window}" x:Key="tkDarkWindowStyle">
<Setter Property="AllowsTransparency" Value="True"></Setter>
<Setter Property="Foreground" Value="{StaticResource tkBrandBlueBrush}"></Setter>
<Setter Property="Background" Value="{StaticResource exQuiteDarkBrush}"></Setter>
<Setter Property="WindowStyle" Value="None"></Setter>
<Setter Property="BorderThickness" Value="0"></Setter>
<Setter Property="BorderBrush" Value="{StaticResource exQuiteDarkBrush}"></Setter>
<Setter Property="WindowChrome.WindowChrome">
<Setter.Value>
<WindowChrome CaptionHeight="80" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Window">
<DockPanel LastChildFill="True">
<Border Background="{TemplateBinding Background}" DockPanel.Dock="Top"
Height="80" x:Name="titlebar">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<DockPanel Grid.Column="0">
<Path DockPanel.Dock="Left" Margin="10" Stretch="Uniform" Fill="{TemplateBinding Foreground}" Data="{Binding Source={StaticResource tkPrimaryLogo}}" VerticalAlignment="Center">
</Path>
<Label Content="{TemplateBinding Title}" Foreground="{TemplateBinding Foreground}" Margin="10" DockPanel.Dock="Left" FontSize="26" VerticalAlignment="Center"/>
</DockPanel>
<ContentPresenter Grid.Column="1"/>
</Grid>
</Border>
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="1" Padding="4">
<ContentPresenter/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I used the style like this and tried to edit the template and add for example some buttons to the titlebar.
<Window.Resources>
<Style TargetType="{x:Type Window}" x:Key="newWindow" BasedOn="{StaticResource tkDarkWindowStyle}">
<!--here add application specific items? -->
</Style>
</Window.Resources>
How can I use the WindowStyle in my application and add specific items to the space i left at the titlebar?
Since the Window only has a single Content property, it makes no sense to include more than one <ContentPresenter /> element in the ControlTemplate.
You may want to create a custom class that inherits from Window and adds a dependency property called "TitleBarContent" or something. You can then add a ContentControl to the template that binds to this property:
<ContentControl Content="{TemplateBinding TitleBarContent}" />
You can set the value of the dependency property in a style setter as usual:
<Style TargetType="{x:Type local:YourWindowClass}" x:Key="newWindow" BasedOn="{StaticResource tkDarkWindowStyle}">
<Setter Property="TitleBarContent">
<Setter.Value>
<TextBlock>title...</TextBlock>
</Setter.Value>
</Setter>
</Style>
An entry in my Application.Resources ResourceDictionary is a control template that, slimmed down, looks similar to the following:
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border>
<Border.BorderBrush>
<SolidColorBrush Color="{Binding Path=BorderColor, RelativeSource={RelativeSource AncestorType=UserControl}" />
</Border.BorderBrush>
</Border>
</ControlTemplate>
Each UserControl has its own property BorderColor which this pulls from. In this example, the binding fails to find the property.
Cannot find source for binding with reference 'RelativeSource
FindAncestor, AncestorType='System.Windows.Controls.UserControl',
AncestorLevel='1''.
However, it works in another entry in the dictionary:
<Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
<Setter Property="BorderBrush" Value="{Binding Path=BorderColor, RelativeSource={RelativeSource AncestorType=UserControl}"/>
</Style>
How can I fix the binding in the first example? Preferably I would like to not need additional properties on the instance of each control in the user control.
Two suggestions:
If the ControlTemplate is part of a Style you could set the BorderBrush property of the ToggleButton to the SolidColorBrush with the binding and use a TemplateBinding in the template:
<Style x:Key="myStyle" TargetType="ToggleButton">
<Setter Property="BorderBrush">
<Setter.Value>
<SolidColorBrush Color="{Binding Path=BorderColor, RelativeSource={RelativeSource AncestorType=UserControl}}" />
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border BorderBrush="{TemplateBinding Background}" BorderThickness="10">
<TextBlock>....</TextBlock>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
If you want to define a standalone ControlTemplate for some reason a workaround would be to bind to a Brush property instead of a Color property:
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border BorderBrush="{Binding Path=BorderBrushProperty, RelativeSource={RelativeSource AncestorType=UserControl}}" BorderThickness="10">
<TextBlock>....</TextBlock>
</Border>
</ControlTemplate>
It works if you use Background instead of BorderColor. Is BorderColor your own property?
<Window.Resources>
<ControlTemplate x:Key="template" TargetType="{x:Type ToggleButton}">
<Border>
<Border.BorderBrush>
<SolidColorBrush Color="{Binding Path=Background,RelativeSource={RelativeSource AncestorType=UserControl}}" />
</Border.BorderBrush>
</Border>
</ControlTemplate>
</Window.Resources>
<UserControl Background="Aqua">
<ToggleButton Template="{StaticResource template}"></ToggleButton>
</UserControl>
I'm styling hyperlinks that appear within a border with the style "FooterPanel" as follows:
<Style x:Key="FooterPanel" TargetType="{x:Type Border}">
<Style.Resources>
<Style TargetType="{x:Type Hyperlink}">
<Setter Property="Foreground" Value="{StaticResource FooterPanelLinkBrush}"/>
</Style>
</Style.Resources>
</Style>
I also now have created a style to create a button as a hyperlink (so I can get properties such as IsDefault and IsCancel on a hyperlink):
<Style x:Key="LinkButton" TargetType="{x:Type Button}">
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<Hyperlink Command="{TemplateBinding Command}" CommandParameter="{TemplateBinding CommandParameter}">
<Run Text="{TemplateBinding Content}"/>
</Hyperlink>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Normal hyperlinks within FooterPanel receive the FooterPanelLinkBrush foreground, but if I use LinkButton within a FooterPanel, the style is not applied. Is there a way to get the ControlTemplate to inherit the styles within the FooterPanel instead of any global hyperlink styles?
Edit:
According to this answer https://stackoverflow.com/a/9166963/2383681 there is special handling that means the Hyperlink won't receive the styles defined in the FooterPanel as it's not derived from Control.
I'm not sure what I'm trying to do is therefore possible without some code-behind, so I think I'm just going to workaround this and create a new style for FooterPanelLinkButton and explicitly reference this for the buttons that are in a footer panel. It would be interesting to know if this is possible however without doing that.
You can create a separate Style for the HyperLink:
<Style x:Key="FooterPanelLink" TargetType="{x:Type Hyperlink}">
<Setter Property="Foreground" Value="{StaticResource FooterPanelLinkBrush}"/>
</Style>
And then use this Style in the Resources of the FooterPanel and LinkButton styles in the following way:
<Style x:Key="FooterPanel" TargetType="{x:Type Border}">
<Style.Resources>
<Style TargetType="Hyperlink" BasedOn="{StaticResource FooterPanelLink}" />
</Style.Resources>
</Style>
<Style x:Key="LinkButton" TargetType="{x:Type Button}">
<Style.Resources>
<Style TargetType="Hyperlink" BasedOn="{StaticResource FooterPanelLink}" />
</Style.Resources>
<Setter Property="Focusable" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<TextBlock HorizontalAlignment="Center" VerticalAlignment="Center">
<Hyperlink Command="{TemplateBinding Command}" CommandParameter="{TemplateBinding CommandParameter}">
<Run Text="{TemplateBinding Content}"/>
</Hyperlink>
</TextBlock>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This way the HyperLink inside the LinkButton will use the color you assigned in the FooterPanelLink style.
I have a WPF menu:
XAML:
<Style x:Key="{x:Type ContextMenu}" TargetType="{x:Type ContextMenu}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ContextMenu}">
<Border Background="#FF171616" CornerRadius="5" BorderBrush="DarkGray" BorderThickness="5" Opacity="0.0">
<StackPanel ClipToBounds="True" Orientation="Vertical" IsItemsHost="True" Margin="5,4,5,4"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Am I using the correct x:Type ContextMenu to alter the drop down visualization? The menu item visual is altered because I've manually changed the style. But it is the context drop down on which I want to apply visuals.
How can I modify the context drop down itself?
Here is a paint sample of what I'm after:
To modify style for menu, you need to override Menu style.
Like below:
<Style TargetType="{x:Type Menu}">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="#FF171616" />
</Style>
Edit: you can actually modify the whole template also, if you like. But I think these properties should get you the visualization you are looking for.