How to Style KeyTips? - wpf

I am trying to find the default style for the KeyTip control; so I can just change the default values and make my own KeyTip Style. But I've had no luck at finding it.
So I've tried this:
<Style x:Key="MainKeyTipStyle" TargetType="KeyTipControl" >
<Setter Property="Background" Value="Green"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Effect" Value="{x:Null}"/>
</Style>
on a normal button:
<Button
x:Name="buttonTEST"
Content="_TEST"
KeyTipService.KeyTip="T"
KeyTipService.KeyTipStyle="{StaticResource MainKeyTipStyle}"
Click="buttonTEST_Click"
/>
When I run my test and press Alt it ends up looking like this:
I would like a solid background color. Not a gradient / fade effect as in my test.
How can I get rid of this default effect?
Any help would be appreciated.
Here are links I've looked at but didn't find helpful:
https://social.msdn.microsoft.com/Forums/vstudio/en-US/e0d1336c-2f95-494b-8c4e-3db8d5ab6761/how-to-style-the-keytip-pop-up-background-in-the-microsoft-ribbon?forum=officegeneral
MSDN - Key Tip Style

Set the Template property to a custom ControlTemplate in your KeyTipControl style:
<Style x:Key="MainKeyTipStyle" TargetType="KeyTipControl" >
<Setter Property="Background" Value="Green"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Effect" Value="{x:Null}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="KeyTipControl">
<Border Name="OuterBorder"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<TextBlock Text="{TemplateBinding Text}" HorizontalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
The default one contains two Border elements.

Related

Trigger set in Style not working as expected

I created a class library containing a style for almost every user control. In my applications i add this style library as a nuget package.
<Style TargetType="{x:Type Button}" x:Key="tkButton">
<Setter Property="Background" Value="{StaticResource exQuiteDarkBrush}"/>
<Setter Property="Foreground" Value="{StaticResource tkLightGrayBrush}"/>
<Setter Property="FontFamily" Value="{StaticResource TKTypeRegular}"/>
<Setter Property="BorderBrush" Value="{StaticResource tkMediumGrayBrush}"/>
<Setter Property="MinHeight" Value="25"/>
<Setter Property="MinWidth" Value="60"/>
<Setter Property="Margin" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Button}">
<Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="BorderBrush" Value="{StaticResource tkBrandBlueBrush}"/>
<Setter Property="Foreground" Value="{StaticResource tkBrandBlueBrush}"/>
</Trigger>
<Trigger Property="UIElement.IsEnabled" Value="False">
<Setter Property="Foreground" Value="{StaticResource tkMediumGrayBrush}"/>
<Setter Property="BorderBrush" Value="{StaticResource tkDarkGrayBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
The library contains for example a simple button. In most Usercontrols i use a trigger
for the IsMouseOver Property to change some colors.
In my Application I'm using the style like this:
<Button Style="{DynamicResource tkButton}" Content="button with ITALIC and BOLD type" FontStyle="Italic" FontWeight="Bold" IsEnabled="{Binding Enabled}"/>
<Button BorderBrush="{StaticResource tkRedBrush}" Style="{DynamicResource tkButton}" Content="button with ITALIC type" FontStyle="Italic" IsEnabled="{Binding Enabled}"/>
The first button adds the style and works as expected when hovering over it.
The second one uses the style, but changes the BorderBrush to red. When hovering over the second Button i expect to change the BorderBrush but it stays red.
The only solution i can imagine is to set the trigger inside the window/application again.
Are there any different solutions to change this behavior?
Move the trigger to the ControlTemplate:
<ControlTemplate TargetType="{x:Type Button}">
<Border x:Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="{StaticResource tkBrandBlueBrush}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
If you put it in the Style, the local value specified by BorderBrush="{StaticResource tkRedBrush}" will take precedence over the value set by Setter: https://learn.microsoft.com/en-us/dotnet/framework/wpf/advanced/dependency-property-value-precedence
You can try to declare your button on the following way, by inheriting tkButton style and overriding the BorderBrush value, because BorderBrush="{StaticResource tkRedBrush}" has higher precedence than style declaration
<Button Content="button with ITALIC type" FontStyle="Italic" IsEnabled="{Binding Enabled}">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource tkButton}">
<Setter Property="BorderBrush" Value="{StaticResource tkRedBrush}"/>
</Style>
</Button.Style>
</Button>

How to change the size of a radio button border?

XAML:
<RadioButton Margin="15" Grid.Row="0" Grid.Column="3" Style=" {StaticResource SpeedButtonStyle}" Content="TEST"/>
Style:
<!-- Speed Button Style -->
<Style x:Key="SpeedButtonStyle" TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource {x:Type ToggleButton}}">
<Setter Property="FontSize" Value="18px"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Background" Value="{StaticResource SidePanelButtonBgInactive}"/>
<Setter Property="Foreground" Value="White"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="{StaticResource SidePanelButtonBgActive}"/>
<Setter Property="Foreground" Value="{StaticResource SidePanelButtonFgActive}"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="BorderThickness" Value="30"/>
<Setter Property="BorderBrush" Value="White" />
<Setter Property="Background" Value="{StaticResource SidePanelButtonBgActive}"/>
<Setter Property="Foreground" Value="{StaticResource SidePanelButtonFgActive}"/>
</Trigger>
</Style.Triggers>
</Style>
I am trying to change the size of the border on my radio button which is styled like a toggle button. I can change the colour of the border but not the size. it seems to be using the default size which is realy thin.
I'm using my templated ToggleRadioButton and you can achieve it by binding BorderThickness to its templated parent.
<Style TargetType="RadioButton" x:Key="SpeedButtonStyle">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<ControlTemplate.Resources>
<Style TargetType="{x:Type ToggleButton}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ToggleButton}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ControlTemplate.Resources>
<ToggleButton IsChecked="{Binding IsChecked, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}"
BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Foreground="{TemplateBinding Foreground}"
Background="{TemplateBinding Background}">
</ToggleButton>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="FontSize" Value="18px"/>
<Setter Property="FontWeight" Value="Normal"/>
<Setter Property="Background" Value="Gray"/>
<Setter Property="Foreground" Value="White"/>
<Style.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Background" Value="Red"/>
<Setter Property="Foreground" Value="DarkRed"/>
</Trigger>
<Trigger Property="IsChecked" Value="True">
<Setter Property="BorderThickness" Value="5"/>
<Setter Property="BorderBrush" Value="White" />
<Setter Property="Background" Value="Green"/>
<Setter Property="Foreground" Value="LightSeaGreen"/>
</Trigger>
</Style.Triggers>
</Style>
EDIT:
I think you had completely different problem. Trigger on IsMouseOver or IsChecked doesn't get rid of default Windows hover colours. So you have to get rid of that, which is achieved but templating ToggleButton with a Border on top of templating your RadioButton with that styled ToggleButton. Note that if you would want to modify it more, you have to bind it's properties in the Border as well in ToggleButton. Difference between TemplateBinding and Binding on TemplatedParent is here and furthermore TemplateBinding is only One Way, so IsChecked should be on TemplatedParent.
This should work now (at least for me it did in new project), just replace the colours.

How to customize textbox and combo box border WPF

Before I post my code let me post image where you can easily notice what's acctually happening:
And as you can see on text boxes, border thickness is not same on every side.
In case of textbox it is much more brighter on the right for example.
Also on combobox there is something like shadow on top and on left side..
How could I fix this, I simply want 1px blue border around my controls..
And here is my code:
<ComboBox Name="cmbComboBoxOne" Height="40" BorderThickness="1" VerticalAlignment="Center" BorderBrush="#0091EA" ></ComboBox>
<TextBox Name="txtTextBoxOne" TextWrapping="Wrap" Text="TextBox" BorderThickness="1" BorderBrush="#0091EA" />
EDIT:
I applied Edit Template Copy, I set border thickness to 1 and colour to purple, and it looks like this:
So guys, again it is not good with thickness:1 px, for example with thickness:2px its awesome, all sides are equal but 2px is too much for me..
Here is my code after I edited template:
<TextBox x:Name="txtName" Grid.Column="1" SnapsToDevicePixels="True" UseLayoutRounding="True" Grid.Row="0" Margin="5,0,10,0" TextWrapping="Wrap" Text="TextBox" Height="40" VerticalAlignment="Center" Style="{DynamicResource TextBoxStyle1}" >
<TextBox.Resources>
<Style x:Key="TextBoxStyle1" TargetType="{x:Type TextBox}">
<Setter Property="BorderBrush" Value="Purple"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Microsoft_Windows_Themes:ClassicBorderDecorator x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" BorderStyle="Sunken" Background="{TemplateBinding Background}">
<ScrollViewer x:Name="PART_ContentHost"/>
</Microsoft_Windows_Themes:ClassicBorderDecorator>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Resources>
</TextBox>
as you can see guys
<Setter Property="BorderBrush" Value="Purple"/>
<Setter Property="BorderThickness" Value="1"/>
are set, but result is somehow same :/
Try to set the SnapsToDevicePixels and/or UseLayoutRounding properties to True:
<ComboBox Name="cmbComboBoxOne" ... SnapsToDevicePixels="True" UseLayoutRounding="True" />
If this doesn't work you could try to modify the control template of the controls. Right-click on them in design mode in Visual Studio 2012+ or Blend and choose Edit Template->Edit a Copy to copy the default templates into your XAML markup and then set the above properties on the Border elements in the generated templates.
Edit: Replace the ClassicBorderDecorator with an ordinary Border element:
<TextBox x:Name="txtName" Grid.Column="1" SnapsToDevicePixels="True" UseLayoutRounding="True" Grid.Row="0" Margin="5,0,10,0" TextWrapping="Wrap" Text="TextBox" Height="40" VerticalAlignment="Center" Style="{DynamicResource TextBoxStyle1}" >
<TextBox.Resources>
<Style x:Key="TextBoxStyle1" TargetType="{x:Type TextBox}">
<Setter Property="BorderBrush" Value="Purple"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.WindowTextBrushKey}}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Resources>
</TextBox>
If you want to customize textbox and combobox border you need to change default style and template of these controls by right click on control and select edit template.

Trying to inherit theme / style and applying additional triggers

I'm trying to work with, and understand XAML hierarchy for styles... in simple, a simple Textbox... seen all over the place for how to set the "disabled" background color based on the "IsEnabled" flag. Great, got that.
Now, I want to have another class derived from TextBox... MyTextBox. For this class, I have a property (not dependency property, so I was using DataTrigger). So, I want to keep all the normal TextBox actions that were working, but now get the new trigger to properly update the background color to some other color.. So, here is what I have. just to clarify, all my static resources for colors are SOLID BRUSHES...
<Style TargetType="TextBox" >
<Setter Property="FontFamily" Value="Courier New" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Foreground" Value="{StaticResource MyForeground}" />
<Setter Property="Background" Value="{StaticResource MyBackground}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border Name="Bd" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true">
<ScrollViewer Name="PART_ContentHost"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{StaticResource MyDisBackground}" />
<Setter TargetName="PART_ContentHost" Property="Background"
Value="MyDisBackground"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- Now, my derived (or so I was hoping) style that just adds additional trigger -->
<Style TargetType="local:MyTextBox" BasedOn="{StaticResource {x:Type TextBox}}" >
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsRequired}" Value="True">
<Setter Property="Background" Value="{StaticResource RequiredBackground}" />
</DataTrigger>
</Style.Triggers>
</Style>
Am I missing something simple?
First, your DataTrigger is looking at the DataContext of your MyTextBox (not the control itself). So look at the control, you'd need to do something like:
<DataTrigger Binding="{Binding Path=IsRequired, RelativeSource={RelativeSource Self}}" Value="True">
<Setter Property="Background" Value="{StaticResource RequiredBackground}" />
</DataTrigger>
Now that will set the MyTextBox.Background property when MyTextBox.IsRequired is true. But dependency property values have a precedence order. So the above will visually change the background used like:
<local:MyTextBox />
In the following case your RequiredBackground brush will not be used. Instead you'll see the MyDisBackground brush:
<local:MyTextBox IsEnabled="False" />
In this case, the ScrollViewer.Background is changed to MyDisBackground and no longer binds to the MyTextBox.Background property. The MyTextBox.Background would still be RequiredBackground, but it's no longer used anywhere.
Finally, in the following case your RequiredBackground brush will not be used.
<local:MyTextBox Background="Yellow" />
Here, the local value (yellow) is at #3 in the precedence list, while the style setter is at #8.
If you make your property a dependency property that defaults to false, then you could do something like:
<Style TargetType="TextBox" >
<Setter Property="FontFamily" Value="Courier New" />
<Setter Property="FontSize" Value="12" />
<Setter Property="Foreground" Value="{StaticResource MyForeground}" />
<Setter Property="Background" Value="{StaticResource MyBackground}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border Name="Bd" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="true">
<ScrollViewer Name="PART_ContentHost"
Background="{TemplateBinding Background}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="local:MyTextBox.IsRequired" Value="False">
<Setter Property="Background" Value="{StaticResource RequiredBackground}" />
<Setter TargetName="PART_ContentHost" Property="Background"
Value="RequiredBackground"/>
</Trigger>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{StaticResource MyDisBackground}" />
<Setter TargetName="PART_ContentHost" Property="Background"
Value="MyDisBackground"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:MyTextBox" BasedOn="{StaticResource {x:Type TextBox}}" />
Eventhough the property doesn't exist for TextBox, it can still get the default value of your dependency property and trigger off it. But since it would be set for a TextBox, that trigger will never be used.

WPF TextBox ugly borders problem

I want to override the default TextBox borders in WPF. I have this style that applies on all TextBoxes.
<!-- StyleTextBox-->
<Style x:Key="StyleTextBox" TargetType="{x:Type TextBox}">
<Setter Property="MinHeight" Value="20" />
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Margin" Value="3"/>
<Setter Property="IsEnabled" Value="{DynamicResource WriteAble}"/>
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="VerticalContentAlignment" Value="Top" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="BorderBrush" Value="{StaticResource ButtonFont_DarkGray}" />
<Style.Triggers>
<!--Resolves multiline textbox vertical alignment problem-->
<Trigger Property="TextWrapping" Value="NoWrap">
<Setter Property="VerticalContentAlignment" Value="Center" />
</Trigger>
</Style.Triggers>
</Style>
I added SnapsToDevicePixels="True" to display borders correctly on LCD monitors.
But, every TextBox seems to be different. Some borders are missing, or gray..
Does anyone know why?
You could try editing the template for the textboxes and changing the border name Bd to a "real" border instead of the chrome one. Like this:
<ControlTemplate x:Key="TextBoxBaseControlTemplate1"
TargetType="{x:Type TextBoxBase}">
<Border x:Name="Bd" SnapsToDevicePixels="True"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" >
<ScrollViewer x:Name="PART_ContentHost"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" TargetName="Bd"
Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
<Setter Property="Foreground"
Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
add this setter to your style to enable the template:
<Setter Property="Template"
Value="{DynamicResource TextBoxBaseControlTemplate1}"/>
WPF tries to be device independent when rendering UI to the monitor, and won't draw things "pixel perfect" unless you tell it to. Try adding this to your style:
<Setter Property="SnapsToDevicePixels" Value="True" />
That should tell WPF to render each 1-pixel-thick border along a single pixel line.
You need do the followings to solve that problem...
SnapsToDevicePixels="True"
Dont specify width, do it with the margins
<Setter Property="BorderBrush" HorizontalAlignment="Left" Margin="2,2,2,2"
Value="{StaticResource DarkGray}" />
Hope this helps :)
I think that the left border and upper border is styled, but the right and buttom border stays gray, although I explicitly said in Style that BorderBrush=MyBrush.
What do you think? What about to try remove the 3D effect from TextBox?

Resources