I have noticed a strange behaviour of TextBox while BorderThickness property is set to 1 - the focus causes the border to change the color (to something like white).
However, if I set the border thickness to something different than 1, say .99 or 1.01 the problem disappears.
Is it the bug in WPF? Or is it intended?
This is the default behavior of the Aero style for TextBoxes. To disable it you would need to restyle the TextBox. You can take the default styles from here (see Download Sample).
In the default Style for TextBoxBase (which TextBox is based on), you will see it uses a ListBoxChrome. This element is defined in the Presentation.Aero assembly and is responsible for rendering the "focused" look. You can simply remove the RenderFocus setting and possibly the RenderMouseOver, or replace it with a Border.
Then you'd want to include that in your application resources.
<LinearGradientBrush x:Key="TextBoxBorder"
StartPoint="0,0" EndPoint="0,20" MappingMode="Absolute">
<LinearGradientBrush.GradientStops>
<GradientStop Color="#ABADB3" Offset="0.05" />
<GradientStop Color="#E2E3EA" Offset="0.07" />
<GradientStop Color="#E3E9EF" Offset="1" />
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
<Style x:Key="{x:Type TextBoxBase}" TargetType="{x:Type TextBoxBase}" BasedOn="{x:Null}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}" />
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" />
<Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="1" />
<Setter Property="AllowDrop" Value="true" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBoxBase}">
<Border x:Name="Bd" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}"
SnapsToDevicePixels="true">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border >
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}" />
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="{x:Type TextBox}" BasedOn="{StaticResource {x:Type TextBoxBase}}" TargetType="{x:Type TextBox}"/>
If you look at the ListBoxChrome class in Reflector (specifically the OnRender method), you can see it will only render the focused look if it's BorderThickness is "1,1,1,1".
Related
Defined implicit DataGridCell style is applied instead of the explicit style set via DataGrid's style (DataGrid.CellStyle property). Why? How does the XAML evaluate, whether to use Implicit style over Explicit in this case?
I am trying to create DataGrid style, which will also set the DataGridCells' style.
Tried removing the Implicit DataGridCell style and everything works as expected, explicit style gets working properly.
How to make them work together?
Also providing the DataGridCell style as DataGrid's style resource works. How? Why?
Implicit Style of the DataGridCell
<!-- Implicit DataGridCell style -->
<Style TargetType="{x:Type DataGridCell}">
<Setter Property="FontSize" Value="14" />
<Setter Property="Background" Value="White" />
<Setter Property="BorderBrush" Value="White" />
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="White" />
<Setter Property="BorderBrush" Value="White" />
</Trigger>
</Style.Triggers>
</Style>
Style of the DataGridCell, which I want to apply
<!-- Explicit DataGridCellStyle -->
<Style x:Key="DataGridCellStyle" TargetType="DataGridCell" BasedOn="{StaticResource {x:Type DataGridCell}}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="BorderThickness" Value="0" />
<Setter Property="Foreground" Value="#ffffff" />
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1"
MappingMode="RelativeToBoundingBox" StartPoint="0.5,0">
<GradientStop Color="#FF3b85c8" Offset="0" />
<GradientStop Color="#FF0668b7" Offset="1" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Trigger>
</Style.Triggers>
</Style>
Style of the DataGrid
<!-- DataGrid style -->
<Style x:Key="BaseDataGrid" TargetType="{x:Type DataGrid}">
<Setter Property="CellStyle" Value="{StaticResource DataGridCellStyle}" />
<!-- Uncommenting this makes the solution works even with Implicit style -->
<!--<Style.Resources>
<Style TargetType="{x:Type DataGridCell}" BasedOn="{StaticResource DataGridCellStyle}"/>
</Style.Resources>-->
</Style>
Simple Datagrid instance
<!-- Data grid itself -->
<DataGrid Style="{StaticResource BaseDataGrid}"
AutoGenerateColumns="True"
ItemsSource="{Binding ModelClasses}">
</DataGrid>
I have an issue setting the Foreground color in a ControlTemplate with triggers.
<LinearGradientBrush x:Key="TabItemDefaultBackgroundBrush" StartPoint="0,0" EndPoint="0,1">
<GradientBrush.GradientStops>
<GradientStopCollection>
<GradientStop Offset="0.0" Color="#FFF" />
<GradientStop Offset="1.0" Color="#EEE" />
</GradientStopCollection>
</GradientBrush.GradientStops>
</LinearGradientBrush>
<SolidColorBrush x:Key="SolidBorderBrush" Color="#888" />
<SolidColorBrush x:Key="TabItemSelectBackgroundBrush" Color="#69C" />
<SolidColorBrush x:Key="PressedBrush" Color="#79C" />
<Style TargetType="{x:Type TabItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TabItem}">
<Grid>
<Border
Name="tabBorder"
MinWidth="150"
MinHeight="50"
Margin="0,0,20,0"
Background="{StaticResource TabItemDefaultBackgroundBrush}"
BorderBrush="{StaticResource SolidBorderBrush}"
BorderThickness="1"
CornerRadius="1,1,1,1">
<Grid>
<Grid >
<TextBlock Name="HeaderHeader">
</TextBlock>
</Grid>
<ContentPresenter
x:Name="ContentSite"
Margin="12,2,12,2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
ContentSource="Header"
RecognizesAccessKey="True" />
</Grid>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="HeaderHeader" Property="Foreground" Value="White" />
<Setter TargetName="tabBorder" Property="Background" Value="{StaticResource TabItemSelectBackgroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
When the tab is selected, the background border 'tabBorder' is set correctly, but the foreground of textblock 'HeaderHeader' does not respond.
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="HeaderHeader" Property="Foreground" Value="White" />
<Setter TargetName="tabBorder" Property="Background" Value="{StaticResource TabItemSelectBackgroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
When I remove the TargetName and set the foreground white (to all components), it does work. (but obviously also the foreground color of everything in the content pre
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Foreground" Value="White" />
<Setter TargetName="tabBorder" Property="Background" Value="{StaticResource TabItemSelectBackgroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
Even stranger, when I put the TargetName back in place, but change the setter property from foreground to background, it DOES work! Then the background is set to white for the selected tab.
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="HeaderHeader" Property="Background" Value="White" />
<Setter TargetName="tabBorder" Property="Background" Value="{StaticResource TabItemSelectBackgroundBrush}" />
</Trigger>
</ControlTemplate.Triggers>
Why on earth is it not working for what I need (=set foreground for selected tab)?!
Aha, I learned something today... I was looking in the wrong direction ! After googling more on "ControlTemplate" something finally sunk in. The ContentPresenter does not show the information of the tab, it shows the label of the tab and nothing more. So my trigger was working just fine, but it was setting the foreground of a textblock which had no meaning at all!
When I change the trigger to which control actually shows the label, it was easy peasy...
<Setter TargetName="ContentSite" Property="TextElement.Foreground" Value="White" />
I did have to use an attached property 'TextElement' in order to be able to set properties on text elements.
I'm trying to change the borderbrush property of a button in a custom template. Changing the background on mouseover using this method works just fine, but the BorderBrush? Nada.
Here's my code:
<Style x:Key="ImageButtonStyle" TargetType="Button">
<Setter Property="OverridesDefaultStyle" Value="True"/>
<Setter Property="Margin" Value="2"/>
<Setter Property="Background" Value="LightGray"/>
<Setter Property="BorderBrush" Value="Blue"/>
<Setter Property="BorderThickness" Value="3"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border Name="border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" Margin="1,0,0,-9">
<ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0,1,1,0" Height="94" Width="101"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="BorderBrush" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Edit: Actually not even the blue borderbrush set at the beggining shows up so that may be of relevance.
Here's where the style is used if of any importance.
<Button Margin="191,10,138,109" Style="{StaticResource ImageButtonStyle}">
<Image/>
</Button>
You create style setting BorderThickness to 3 but then override default visual tree so this thicknes is not taken into acount. Add this
BorderThickness="{TemplateBinding BorderThickness}"
in order to see it.
I'm working on a wpf application and I'm wondering how to change the blueish border when the textbox is selected.
I've created a custom style for my textbox
<Window.Resources>
<LinearGradientBrush x:Key="TextBoxBorder" EndPoint="0,20" MappingMode="Absolute" StartPoint="0,0">
<GradientStop Color="#ABADB3" Offset="0.05"/>
<GradientStop Color="#E2E3EA" Offset="0.07"/>
<GradientStop Color="#E3E9EF" Offset="1"/>
</LinearGradientBrush>
<Style x:Key="CustomTextbox" BasedOn="{x:Null}" TargetType="{x:Type TextBox}">
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource TextBoxBorder}"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Padding" Value="1"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
<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:ListBoxChrome x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Microsoft_Windows_Themes:ListBoxChrome>
<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>
<Trigger Property="IsFocused" Value="true">
<Setter Property="BorderBrush" Value="Red"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
I tried to set the borderbrush red when the focus is true, but that doesn't have any effect.
Try setting the highlightbrushes to transparent as below:
<Style TargetType="TextBox">
<Style.Resources>
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" color="Transparent" />
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent" />
</Style.Resources>
I suggest changing the template a little bit including an actual Border that sets properties related to it.
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}" >
<Microsoft_Windows_Themes:ListBoxChrome x:Name="Bd" RenderMouseOver="{TemplateBinding IsMouseOver}" RenderFocused="{TemplateBinding IsKeyboardFocusWithin}" SnapsToDevicePixels="true">
<ScrollViewer x:Name="PART_ContentHost" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Microsoft_Windows_Themes:ListBoxChrome>
</Border>
Triggers would remain as you set them. Hope this helps!
I am working on a simple textBox template, which is just two borders, one with a gradient background. Now, my specific issue is that I want to be able to set the foreground color of the textBox to whatever color I want and have it work correctly. However, I can't seem to get both the disabled foreground and enabled foreground colors to work together. If I set the foreground to red for example, when I disable the textBox, the foreground doesn't get changed to my disabled color. I tried binding the foreground in the IsEnabled="true" trigger but that doesn't seem to work. The foreground always stays red, no matter if the textBox is enabled or not.
Can you please take a look at the below template and tell me what I am doing wrong? Also, please point out to me any other mistakes I may have made since I am new at creating templates.
Thanks a lot.
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
<SolidColorBrush x:Key="WindowBackgroundBrush" Color="#FFF" />
<SolidColorBrush x:Key="SelectedBackgroundBrush" Color="#DDD" />
<Style x:Key="TextBoxControlTemplate1" TargetType="{x:Type TextBox}">
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="Background" Value="#00000000"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Padding" Value="8,5,3,3"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<Border BorderBrush="#FF000000" BorderThickness="2,2,2,2" CornerRadius="5,5,5,5" Padding="0,0,0,0" Width="Auto" Height="Auto" Background="#FF000000"/>
<Border x:Name="Border" BorderBrush="#FFFFFFFF" BorderThickness="1,1,1,1" CornerRadius="5,5,5,5" Padding="0,0,0,0" Width="Auto" Height="Auto" Margin="2,2,2,2">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FF4D4D4D" Offset="1"/>
</LinearGradientBrush>
</Border.Background>
</Border>
<ScrollViewer Margin="0" x:Name="PART_ContentHost"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
<Setter Property="BorderBrush" Value="{DynamicResource DisabledBackgroundBrush}" TargetName="Border"/>
<Setter Property="Foreground" Value="{DynamicResource DisabledForegroundBrush}"/>
</Trigger>
<Trigger Property="IsEnabled" Value="True">
<Setter Property="Foreground" Value="{Binding Path=Foreground, RelativeSource={RelativeSource AncestorType={x:Type TextBox}}}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<TextBox Text="TEST" TextWrapping="Wrap" Canvas.Top="293.761" Canvas.Left="112" Style="{DynamicResource TextBoxControlTemplate1}" Height="28.724" Width="232.25" IsTabStop="False" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" IsEnabled="True" Foreground="#FFFF0000"/>
There are a few different issues here all working against you. The first is that you're setting a specific Foreground value on your control instance, which has a higher priority than values set from Triggers in your Style for properties of the control itself. This is different than properties set on elements inside the ControlTemplate, like "Border". The way you're using Triggers to set the Border properties is illustrating that. Normally you would also want to use TemplateBindings to pull in values set on your control instance as defaults, like Background, which are currently being ignored.
To switch between two values of a property on your styled control, like you want to do with Foreground, you can use a Setter and a Trigger in your Style to provide a default and alternate value. This is still subject to being overridden by a value set on an instance. If you want to disallow instances overriding a Trigger set it up like the "Border" Trigger where you're setting values on elements inside the ControlTemplate.
The last change I'd recommend is switching to StaticResource for the Brushes you're pulling into your Style. In this case it probably won't make a difference, but in some cases a default Style can get pulled into a context that doesn't have any reference to the surrounding Resources from the file it was declared in. Using Static will guarantee that it will include those Resources no matter where it gets used. You may not run into this but it's a good habit to get into when setting up Styles/Templates like this.
Here's your code with those improvements:
<SolidColorBrush x:Key="DisabledForegroundBrush" Color="#888" />
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
<Style x:Key="TextBoxControlTemplate1" TargetType="{x:Type TextBox}">
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="AllowDrop" Value="true"/>
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FF000000" Offset="0"/>
<GradientStop Color="#FF4D4D4D" Offset="1"/>
</LinearGradientBrush>
</Setter.Value>
</Setter>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="VerticalContentAlignment" Value="Stretch"/>
<Setter Property="FontFamily" Value="Segoe UI"/>
<Setter Property="FontSize" Value="12"/>
<Setter Property="Padding" Value="8,5,3,3"/>
<Setter Property="BorderThickness" Value="2"/>
<Setter Property="BorderBrush" Value="#FF000000"/>
<Setter Property="Foreground" Value="Red" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Grid>
<!--Take advantage of containment when possible to let the layout engine help you!-->
<Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="5" Padding="0" Background="#FF000000"/>
<Border x:Name="Border" BorderBrush="#FFFFFFFF" BorderThickness="1" CornerRadius="5" Padding="0" Margin="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"/>
<ScrollViewer Margin="0" x:Name="PART_ContentHost"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Background" Value="{StaticResource DisabledBackgroundBrush}" TargetName="Border"/>
<Setter Property="BorderBrush" Value="{StaticResource DisabledBackgroundBrush}" TargetName="Border"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Setter Property="Foreground" Value="{StaticResource DisabledForegroundBrush}"/>
</Trigger>
</Style.Triggers>
</Style>
And the TextBox using only the Style settings:
<TextBox Text="TEST" TextWrapping="Wrap" Canvas.Top="293.761" Canvas.Left="112" Style="{DynamicResource TextBoxControlTemplate1}"
Height="28.724" Width="232.25" IsTabStop="False" HorizontalContentAlignment="Right" VerticalContentAlignment="Center" />
A couple ideas to try:
Get rid of one of your triggers. Having two opposing triggers may not be a good idea. I would set the default Background, BorderBrush, and Foreground directly on your Border declaration, and remove the Enabled="True" trigger. Then, debugging is only a matter of getting the Enabled="False" trigger right.
Add the TargetName property to setter for your Enabled="False" trigger.
This is a longshot, but use UIElement.IsEnabled instead of just IsEnabled, like this: <Trigger Property="UIElement.IsEnabled">.
Hope something I've said here helps!
The possible reason is that your DisabledBackgroundBrush is not visible at the point where you use your style. Please try to add the styles into the ControlTemplate's resources:
<ControlTemplate TargetType="{x:Type TextBox}">
<ControlTemplate.Resources>
<SolidColorBrush x:Key="DisabledBackgroundBrush" Color="#EEE" />
...
</ControlTemplate.Resources>
...
By the way, your control template doesn't honour the values of your properties.
For example, you should perhaps use something like
<ScrollViewer Margin="{TemplateBinding Padding}" x:Name="PART_ContentHost"/>
in your control template.