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?
Related
I am new to WPF and I am trying to do a rounded corner textbox. There are a lot of examples I gather from here. However I cannot seems to make it work. Below are the two ways I tried and the results I obtained.
First Way:
<SolidColorBrush x:Key="SubTransparentTextBoxBG" Color="#ffffff" Opacity="0.12"/>
<Style TargetType="TextBox">
<Style.Setters>
<Setter Property="Background" Value="{StaticResource SubTransparentTextBoxBG}" />
<Setter Property="FontSize" Value="24px" />
<Setter Property="FontFamily" Value="Segoe UI Semibold"/>
<Setter Property="Foreground" Value="White" />
<Setter Property="Padding" Value="10" />
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BorderThickness" Value="2"/>
</Style.Setters>
<Style.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</Style.Resources>
</Style>
Result:
Apparently all my Setters took effect but not the Corner Radius
Second Way:
<SolidColorBrush x:Key="SubTransparentTextBoxBG" Color="#ffffff" Opacity="0.12"/>
<Style TargetType="TextBox">
<Style.Setters>
<Setter Property="Background" Value="{StaticResource SubTransparentTextBoxBG}" />
<Setter Property="FontSize" Value="24px" />
<Setter Property="FontFamily" Value="Segoe UI Semibold"/>
<Setter Property="Foreground" Value="White" />
<Setter Property="Padding" Value="10" />
<Setter Property="BorderBrush" Value="Red" />
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border x:Name="border" CornerRadius="10" BorderBrush="#000" BorderThickness="2" Background="#fff"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Result:
This time, only the Round Border takes place and the rest of the Setters' property are overwritten.
Can Someone Please Help to point out what are the mistakes in these two ways?
The best way to give the TextBox rounded corners is to overwrite the template.
The following is your Style, but fixed. It now contains the mandatory parts with their mandatory naming: a content host named PART_ContentHost. In order to make the style setters work, you need to bind the template's controls (in this case the Border properties) to the appropriate properties of the templated parent (the TextBox) using TemplateBinding.
<Style TargetType="TextBox">
<Style.Setters>
<Setter Property="Background"
Value="{StaticResource SubTransparentTextBoxBG}" />
<Setter Property="FontSize"
Value="24px" />
<Setter Property="FontFamily"
Value="Segoe UI Semibold" />
<Setter Property="Foreground"
Value="White" />
<Setter Property="Padding"
Value="10" />
<Setter Property="BorderBrush"
Value="Red" />
<Setter Property="BorderThickness"
Value="2" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Border CornerRadius="10"
Margin="{TemplateBinding Margin}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Padding="{TemplateBinding Padding}">
<!-- The required part with the required name -->
<ScrollViewer x:Name="PART_ContentHost"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style.Setters>
</Style>
Wrapping the TextBox in a Border with rounded corners will still leave the TexBox with sharp corners that will overlap the rounded corners of the surrounding Border.
Some controls have mandatory template elements (parts) which must be part of the ContorlTemplate and have a special name. When those parts are missing or the name doesn't match the required name, then the functionality of the templated control might get broken. To know the parts and their names of TextBox visit TextBox Parts. To know the named parts of all WPF controls visit Control Styles and Templates. This links also contains an example of the actual Style and Template.
An alternative approach to get the required template parts is to select the control you wish to template and then open the XAML designer view. Right click on the selected control and select Edit Template. In the popup select Edit a Copy. A dialog opens. Here you can give the extracted template a name and set the location where the extracted template will be moved to. Now you can edit this template which already has all the required parts.
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.
I have built an UserControl. I don't like the red border showing around it when validation errors occur. I have a textbox inside my control.
How can I override the validation error style to get rid of the red border in the whole control and just show a red background in the textbox inside my usercontrol?
Thanks!
I am using this template that will color the background of the textbox instead of showing just the border.
<UserControl.Resources>
<Style TargetType="{x:Type TextBox}">
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true" >
<Setter Property="Foreground" Value="Red"/>
<Setter Property="Background" Value="MistyRose"/>
<Setter Property="BorderBrush" Value="Red"/>
<Setter Property="BorderThickness" Value="1.0"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="ToolTip" Value="{Binding RelativeSource={RelativeSource
Self},Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
And all I have to do to your DocPannel Where the controls are located for example for me inside a DockPanel then i have to set its Validation.Error template to nothing this will remove the border.
For Ex:
<TextBox >
<Validation.ErrorTemplate>
<ControlTemplate>
</ControlTemplate>
</Validation.ErrorTemplate>
</TextBox>
On the style for your user control:
<Setter Property="Validation.ErrorTemplate" Value="{x:Null}"/>
On the style for your textbox:
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBoxBase}">
<Border
Name="Border"
CornerRadius="5"
Padding="2"
BorderBrush="{TemplateBinding BorderBrush}"
Background="{TemplateBinding Background}"
BorderThickness="{TemplateBinding BorderThickness}" >
<ScrollViewer Margin="0" x:Name="PART_ContentHost"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter TargetName="Border" Property="Background" Value="LightGray"/>
<Setter TargetName="Border" Property="BorderBrush" Value="Black"/>
<Setter Property="Foreground" Value="Gray"/>
</Trigger>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="BorderBrush" TargetName="Border" Value="{DynamicResource ErrorBorderColor}"/>
<Setter Property="Background" TargetName="Border" Value="{DynamicResource ErrorBackgroundColor}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
I have a CheckBox object and it doesn't have any text associated with it.
It is in a Grid which has another coulmn used as the label for it.
The whitespace next to the checkbox you can click and it will toggle checkbox
I want it just be the area of the actual checkbox and not the white space around it(because the text for it is set to nothing).
I tried setting the width = 5 but that didn't make a difference
thank you very much!!
It sounds like your CheckBox is stretching to the whole width of the grid cell (with all of that width clickable), and you don't want it to stretch.
Set the CheckBox's HorizontalAlignment property to Left (or Center, or Right). Then it will be exactly the width it needs to be for the checkbox, rather than stretching to the entire width provided by its parent.
For that you will have to go into the checkboxes template and modify that. Specifically you should go in and remove the ContentPresenter which is what displays the text. Since you have no text, it is not a problem. The end result will look something like this. Just add that style to your checkbox.
The default templates ContentPresenter is housed under the Bullet. Because of this, clicking on that content presenter (even if empty, I think it has a default size) will activate the controls click logic.
<Style x:Key="CheckBoxStyle1" TargetType="{x:Type CheckBox}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Background" Value="{StaticResource CheckRadioFillNormal}"/>
<Setter Property="BorderBrush" Value="{StaticResource CheckRadioStrokeNormal}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="FocusVisualStyle" Value="{StaticResource EmptyCheckBoxFocusVisual}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type CheckBox}">
<BulletDecorator Background="Transparent" SnapsToDevicePixels="true">
<BulletDecorator.Bullet>
<Microsoft_Windows_Themes:BulletChrome BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" IsChecked="{TemplateBinding IsChecked}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderPressed="{TemplateBinding IsPressed}"/>
</BulletDecorator.Bullet>
</BulletDecorator>
<ControlTemplate.Triggers>
<Trigger Property="HasContent" Value="true">
<Setter Property="FocusVisualStyle" Value="{StaticResource CheckRadioFocusVisual}"/>
<Setter Property="Padding" Value="2,0,0,0"/>
</Trigger>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I want to create a custom control type that behaves exactly like a ListBox, except that it displays with a heading above it.
I think what I need to do is inherit from ListBox and use code like the following:
var originalTree = Template.VisualTree;
var panel = new FrameworkElementFactory(typeof(StackPanel));
var heading = new FrameworkElementFactory(typeof(TextBlock));
heading.SetValue(TextBlock.TextProperty, "Heading");
panel.AppendChild(heading);
panel.AppendChild(originalTree);
Template.VisualTree = panel;
Except wherever I tried to place it, it didn't work, because Template.VisualTree was null. What am I doing wrong?
As far as i know templates can be defined in various ways, if the VisualTree is null, it has been generated 'by reference', in that case it has been set with Frameworktemplate.Template.
(Editing that is not intended, all members are internal or private)
I would use a UserControl if you are going to take the whole root anyway.
Edit: Copying and editing the default template should be fine as well, here is the default style:
<SolidColorBrush x:Key="ListBorder" Color="#828790"/>
<Style TargetType="{x:Type ListBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource ListBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Auto"/>
<Setter Property="ScrollViewer.CanContentScroll" Value="true"/>
<Setter Property="ScrollViewer.PanningMode" Value="Both"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="1" SnapsToDevicePixels="true">
<ScrollViewer Focusable="false" Padding="{TemplateBinding Padding}">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</ScrollViewer>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
(You could bind the header TextBox.Text to the ListBox.Tag then you do not need to subclass it)
Default templates and styles are on MSDN.
This article http://www.wpftutorial.net/CustomVsUserControl.html implies that a UserControl is a conglomerate of several controls - in your case a Label or TextBlock plus a ListBox? So is a user control a possible solution?