I have a custom textbox control in which I want to draw a horizontal line when a certain property is true and then remove the line when the property is false. The line needs to have a width that is -2 of the control width and be at a height of -5 from the control bottom. I am currently using an Adorner with the following OnRender
to accomplish this behavior:
protected override void OnRender(System.Windows.Media.DrawingContext drawingContext)
{
base.OnRender(drawingContext);
var rect = new Rect(AdornedElement.RenderSize);
rect.Inflate(-2, -5);
// ColoredPen is a custom class that holds a Pen object
drawingContext.DrawLine(ColoredPen.Pen, rect.BottomLeft, rect.BottomRight);
}
I am running into some issues where the Adorner is not refreshing properly and so it disappears even when the related property is true
. I have tried several different ways of ensuring the Adorner is refreshed but it is failing miserably. I believe the Adorner approach is not really the proper approach to my problem. I think it would be better if I used a ControlTemplate with the property as a trigger. For simple example case, we can use the IsFocused
property. This is the code that I have thus far, but I am unsure as to how to set the X and Y properties of the Line and really how to make it work. This current code just crashes the application (and yes, I know that the dimensions for the line set in this code are not what I want, this was my attempt to just make the line appear, I figured I could tweak it from there).
<Style x:Key="TextBoxUnderlineTemplate" TargetType="myUi:MyTextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="myUi:MyTextBox">
<Line Name="UnderlineStuff" Stroke="Black" X1="0"
X2="{Binding RelativeSource={RelativeSource Self}, Path=Width}"
Y1="{Binding RelativeSource={RelativeSource Self}, Path=Height}"
Y2="{Binding RelativeSource={RelativeSource Self}, Path=Height}"
StrokeThickness="2" Visibility="Collapsed"/>
<ControlTemplate.Triggers>
<Trigger Property="IsFocused" Value="True">
<Setter TargetName="UnderlineStuff" Property="Visibility" Value="Visible"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
So, I am looking for a way to make this work with a ControlTemplate, or if there is another suggestion of how to make this work, that would also be acceptable (an Adorner is out). Note that once this is working I will need to be able to add a second line a little lower than this line depending on an additional property.
This presents an underline on IsMouseOver
. You may need to improve the very simple converter implementation, which is based on font size:
XAML:
<Window x:Class="WpfApplication363.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication363"
mc:Ignorable="d"
Title="MainWindow" Height="300" Width="300">
<Window.Resources>
<local:MyConverter x:Key="conv1"/>
<SolidColorBrush x:Key="TextBox.Static.Border" Color="#FFABAdB3"/>
<SolidColorBrush x:Key="TextBox.MouseOver.Border" Color="#FF7EB4EA"/>
<SolidColorBrush x:Key="TextBox.Focus.Border" Color="#FF569DE5"/>
<Style x:Key="TextBoxStyle1" TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{DynamicResource {x:Static SystemColors.WindowBrushKey}}"/>
<Setter Property="BorderBrush" Value="{StaticResource TextBox.Static.Border}"/>
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
<Setter Property="BorderThickness" 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}">
<Grid>
<Border x:Name="border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
</Border>
<Line x:Name="line1"
Y1="{TemplateBinding FontSize, Converter={StaticResource conv1}}"
X2="{Binding ElementName=border, Path=ActualWidth}"
Y2="{TemplateBinding FontSize, Converter={StaticResource conv1}}"
Stroke="Red"
Visibility="Hidden"/>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter Property="Opacity" TargetName="border" Value="0.56"/>
</Trigger>
<Trigger Property="IsMouseOver" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.MouseOver.Border}"/>
<Setter Property="Visibility" TargetName="line1" Value="Visible"/>
</Trigger>
<Trigger Property="IsKeyboardFocused" Value="true">
<Setter Property="BorderBrush" TargetName="border" Value="{StaticResource TextBox.Focus.Border}"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsInactiveSelectionHighlightEnabled" Value="true"/>
<Condition Property="IsSelectionActive" Value="false"/>
</MultiTrigger.Conditions>
<Setter Property="SelectionBrush" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
</MultiTrigger>
</Style.Triggers>
</Style>
</Window.Resources>
<Grid>
<TextBox Style="{DynamicResource TextBoxStyle1}"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="24"
Text="Textbox with underline !"/>
</Grid>
Converter:
public class MyConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return ((double)value) + 4;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.