Can anyone explain why the TextBox resource style of CornerRadius works just fine, but BorderThickness and BorderBrush have zero effect?
<TextBox Text="TextBox with CornerRadius but no thickness and color"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
VerticalAlignment="Center" Width="500" Height="100">
<TextBox.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="30" />
<Setter Property="BorderThickness" Value="30" />
<Setter Property="BorderBrush" Value="Red" />
</Style>
</TextBox.Resources>
</TextBox>
The BorderThickness and BorderBrush of the Border element in the Template of a TextBox are bound to the respectice properties of the templated control, i.e. the TextBox:
<ControlTemplate TargetType="TextBox">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" ...>
...
</Border>
</ControlTemplate>
These Bindings override the values from any Border Style Setters.
You should set the values in a TextBox Style:
<TextBox Text="TextBox with CornerRadius but no thickness and color"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
VerticalAlignment="Center" Width="500" Height="100">
<TextBox.Style>
<Style TargetType="TextBox">
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="30"/>
</Style>
</Style.Resources>
<Setter Property="BorderThickness" Value="30"/>
<Setter Property="BorderBrush" Value="Red"/>
</Style>
</TextBox.Style>
</TextBox>
The reason is that in the standard TextBoxBase's template the Border control has its properties BorderThickness and BorderBrush bound to the same properties of the TextBox itself.
Here the standard ControlTemplate used in the style:
<ControlTemplate TargetType="{x:Type TextBoxBase}">
<cbd:ClassicBorderDecorator x:Name="Bd" BorderStyle="Sunken" Background="{TemplateBinding Control.Background}" BorderThickness="{TemplateBinding Control.BorderThickness}" BorderBrush="{TemplateBinding Control.BorderBrush}">
<ScrollViewer Name="PART_ContentHost" />
</cbd:ClassicBorderDecorator>
<ControlTemplate.Triggers>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" Property="theme:ClassicBorderDecorator.Background" />
<Setter Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" Property="Control.Foreground" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
So to reach your target those properties can be set in this way:
<TextBox Text="TextBox with CornerRadius but no thickness and color"
HorizontalContentAlignment="Center" BorderThickness="30" BorderBrush="Red"
VerticalContentAlignment="Center"
VerticalAlignment="Center" Width="500" Height="100">
<TextBox.Resources>
<Style TargetType="{x:Type Border}">
<Setter Property="CornerRadius" Value="30" />
</Style>
</TextBox.Resources>
</TextBox>
I hope it can help you.
Related
I have this button and wanted to change the design if I hover over it with the mouse. It's not working and I'm not getting an error.
What am I doing wrong?
(I'm really new to WPF)
<Button MaxWidth="180"
Margin="5"
DockPanel.Dock="Top"
Padding="5"
FontSize="12"
Foreground="#1261AC"
FontWeight="SemiBold"
BorderBrush="Transparent">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border CornerRadius="5" Background="LightGray" BorderThickness="1" Padding="5">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Foreground" Value="#157ec4"/>
<Setter Property="Background" Value="#000000"/>
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
The button itself is working but it is not chaning the color of the background or font.
(The colors in my example are just for testing)
The problem with your code is that you define the border-background to be gray.
Now you change the control background using a trigger.
However, the background that is set by the trigger is not yet related to the border background in your example.
I added a template binding that fixes this issue to you. Now the border in your template will always have the Background defined in your style, set by triggers or directly set in XAML.
PLEASE NOTE:
If you set the color in XAML by using <Button Background="Pink"/> this will overwrite the style and trigger attributes.
if you still want to overwrite the background property for a single button for some reason without overwritting the triggers you'll have to create a style based on the original style using the BasedOn Property:
<Style TargetType="Button" BasedOn="{StaticResource {x:Type Button}}">
<Setter Propert="Background" Value="Yellow"/>
</Style>
try this piece of art:
ButtonStyle:
<Button Content="Hello there!"
MaxWidth="180"
Margin="5"
DockPanel.Dock="Top"
Padding="5"
FontSize="12"
Foreground="#1261AC"
FontWeight="SemiBold"
BorderBrush="Transparent">
<Button.Style>
<Style TargetType="Button">
<Setter Property="Background" Value="HotPink"></Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border CornerRadius="5" Background="{TemplateBinding Background}" BorderThickness="1" Padding="5">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red" />
<Setter Property="Background" Value="Lime" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
I can create a standard WPF window as follows, and all works fine.
<Window x:Class="WpfWindowStyleTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
AllowsTransparency="True"
Background="Transparent"
ResizeMode="CanResizeWithGrip"
SizeToContent="WidthAndHeight"
TextOptions.TextFormattingMode="Display"
TextOptions.TextRenderingMode="ClearType"
Topmost="True"
UseLayoutRounding="True"
WindowStyle="None">
<Grid>
<Border Background="LightGreen"
BorderBrush="Navy"
BorderThickness="2"
CornerRadius="4">
// window content here ...
</Border>
</Grid>
</Window>
However, my application requires a number of common components (way beyond a simple border) to be shared by all windows, so I tried to extract it into a common class.
public class BaseView: Window
{
static BaseView()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(BaseView), new FrameworkPropertyMetadata(typeof(BaseView)));
}
}
with the following style in generic.xaml
<Style BasedOn="{StaticResource {x:Type Window}}" TargetType="{x:Type local:BaseView}">
<Setter Property="AllowsTransparency" Value="True" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="SizeToContent" Value="WidthAndHeight" />
<Setter Property="TextOptions.TextFormattingMode" Value="Display" />
<Setter Property="TextOptions.TextRenderingMode" Value="ClearType" />
<Setter Property="Topmost" Value="True" />
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="WindowStyle" Value="None" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:BaseView}">
<Grid>
<AdornerDecorator>
<Border Background="LightGreen"
BorderBrush="Navy"
BorderThickness="2"
CornerRadius="4">
<ContentPresenter Margin="24" HorizontalAlignment="Left" />
</Border>
</AdornerDecorator>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
This works fine.
However, when I add another property setter to the style
<Setter Property="ResizeMode" Value="CanResizeWithGrip" />
The whole control template is ignored, and just the specified window content is displayed (in an empty, resizable window).
Is there any way around this?
Your issue depends on the standard Window style; take a look:
<Style x:Key="{x:Type Window}" TargetType="{x:Type Window}">
<Setter Property="Control.Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}" />
<Setter Property="Control.Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter Property="Control.Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<Border Background="{TemplateBinding Control.Background}" BorderBrush="{TemplateBinding Control.BorderBrush}" BorderThickness="{TemplateBinding Control.BorderThickness}">
<AdornerDecorator>
<ContentPresenter />
</AdornerDecorator>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Window.ResizeMode" Value="CanResizeWithGrip">
<Setter Property="Control.Template" Value="{StaticResource ħ}" />
</Trigger>
</Style.Triggers>
</Style>
As you can see, if the ResizeMode is set to CanResizeWithGrip, a trigger changes the Window's template.
A simple solution could be adding a ResizeGrip to your template and avoing that your style inherits from the default one. Something like:
<Style TargetType="{x:Type local:BaseView}">
<Setter Property="AllowsTransparency" Value="True" />
<Setter Property="Background" Value="Transparent" />
<Setter Property="SizeToContent" Value="WidthAndHeight" />
<Setter Property="TextOptions.TextFormattingMode" Value="Display" />
<Setter Property="TextOptions.TextRenderingMode" Value="ClearType" />
<Setter Property="Topmost" Value="True" />
<Setter Property="UseLayoutRounding" Value="True" />
<Setter Property="WindowStyle" Value="None" />
<Setter Property="ResizeMode" Value="CanResizeWithGrip" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:BaseView}">
<Grid>
<AdornerDecorator>
<Border Background="LightGreen"
BorderBrush="Navy"
BorderThickness="2"
CornerRadius="4">
<ContentPresenter Margin="24" HorizontalAlignment="Left" />
</Border>
</AdornerDecorator>
<ResizeGrip Name="WindowResizeGrip" HorizontalAlignment="Right" VerticalAlignment="Bottom" IsTabStop="False" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I hope it can help you.
Please keep in mind i am new with WPF, I am trying to give my Button a border thickness value via .Xaml templates, However, its not working, Here is my .Xaml:
<Button>
<Button.Style>
<Style TargetType="{x:Type Button}">
<Setter Property="Background" Value="#FFFFFFFF" />
<Setter Property="Foreground" Value="#FFF01F1F" />
<Setter Property="BorderBrush" Value="#FFF01F1F" />
<Setter Property="BorderThickness" Value="5" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="#FFF01F1F" />
<Setter Property="Foreground" Value="#FFFFFFFF" />
</Trigger>
</Style.Triggers>
</Style>
</Button.Style>
</Button>
Thanks in Advance.
Update:::
I have tried the Change Thickness answer, however now it disables my IsMouseOver property,
You set your own custom template which doesn't use the BorderThickness property of the button itself, so it should be:
<Border Background="{TemplateBinding Background}" BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
Or you can set it to 5 directly on the template.
I want to change the color of a MenuItem at mouseOver. I need also rounded borders, an image and a textBox. When I set the style all is ok only the mouseOverEvent is doing anything, the background doesnot change. My code is:
<Style x:Key="BaseStyle" TargetType="MenuItem">
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="Background" Value="#0a99f3" />
</Trigger>
<Trigger Property="IsKeyboardFocusWithin" Value="true">
<Setter Property="Background" Value="#0a99f3" />
</Trigger>
</Style.Triggers>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type MenuItem}">
<Grid>
<Border Name="MainBorder" BorderThickness="2,2,2,0" CornerRadius="8,8,8,8" Margin="0,0,1,0" BorderBrush="AliceBlue">
<Grid>
<TextBlock Text="Info" Margin="30,10,0,0" FontFamily="Arial" FontSize="14" FontWeight="Bold" />
<Image Width="15" Height="15" Source="menu.PNG" Margin="-100,0,0,0" />
</Grid>
</Border>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Hope anybody know what I am missing. Thanks!
You're overwritting the Template, but not using the Background Color anywhere in it so the value never gets applied.
Set the Background Color in your MenuItem Template
<ControlTemplate TargetType="{x:Type MenuItem}">
<Grid Background="{TemplateBinding Background}">
You are not binding the Background anywhere in your template so changing that property has no effect.
I am using IDataErrorInfo to validate and indicate errors in my text boxes. I am finding I have to tab once for the text box and once for the adornerdecorator.
I have an error template:
<ControlTemplate x:Key="ErrorTemplate">
<StackPanel KeyboardNavigation.IsTabStop="False" >
<Border KeyboardNavigation.IsTabStop="False" BorderBrush="Red" BorderThickness="1" Padding="2" CornerRadius="2">
<AdornedElementPlaceholder KeyboardNavigation.IsTabStop="False" />
</Border>
</StackPanel>
</ControlTemplate>
a textbox template:
<Style x:Key="TextBoxInError" TargetType="{x:Type TextBox}">
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="Margin" Value="0,5,0,5"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="HorizontalContentAlignment" Value="left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid KeyboardNavigation.IsTabStop="False" >
<Border KeyboardNavigation.IsTabStop="False" x:Name="Border" Background="{DynamicResource WindowBackgroundBrush}" BorderBrush="{DynamicResource SolidBorderBrush}" BorderThickness="1" Padding="2" CornerRadius="2">
<ScrollViewer IsTabStop="False" Margin="0" x:Name="PART_ContentHost" Style="{DynamicResource SimpleScrollViewer}" Background="{TemplateBinding Background}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource Self}, Path=(Validation.Errors), Converter={StaticResource errorConverter}}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="Gray"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
and declare a text box like this:
<AdornerDecorator KeyboardNavigation.IsTabStop="False" >
<TextBox Margin="5,5,5,3" x:Name="txtName" IsEnabled="{Binding EditMode}" Validation.ErrorTemplate="{StaticResource ErrorTemplate}"
Text="{Binding ApplicationName, Mode=TwoWay, ValidatesOnExceptions=True, NotifyOnValidationError=True, ValidatesOnDataErrors=True}"
Height="25" MaxLength="50" MaxLines="1" Style="{StaticResource TextBoxInError}"/>
</AdornerDecorator>
If the adorner is round one text box as above then I tab once to leave the text box and once to leave the 'adornment' (it seems) If I have the adorner around a stackpanel of text boxes then I tab once each for the text boxes then have to go back through all the 'adornments' in turn. When tabbing through the adornments the focus goes on the red border defined in the control template..
any ideas?
thanks
Add this to the window's resources section:
<Style TargetType="{x:Type Control}">
<Setter Property="Focusable" Value="False"/>
</Style>
For more information look at my blog: http://www.nbdtech.com/blog/archive/2008/05/25/WPF-Problems-with-Keyboard-Focus-When-Using-Validation.aspx