Oval TextBox
My project require an oval text box. First place I started to make my changes is in the default template of Textbox. The default template of any control can be retrieved through expression blend (Right click on the Control and select Edit Template/Edit a Copy).
Below is the default template of TextBox control
<UserControl.Resources> <ControlTemplate x:Key="ValidationToolTipTemplate"> <Grid x:Name="Root" Margin="5,0" Opacity="0" RenderTransformOrigin="0,0"> <Grid.RenderTransform> <TranslateTransform x:Name="xform" X="-25"/> </Grid.RenderTransform> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="OpenStates"> <VisualStateGroup.Transitions> <VisualTransition GeneratedDuration="0"/> <VisualTransition GeneratedDuration="0:0:0.2" To="Open"> <Storyboard> <DoubleAnimation Duration="0:0:0.2" To="0" Storyboard.TargetProperty="X" Storyboard.TargetName="xform"> <DoubleAnimation.EasingFunction> <BackEase Amplitude=".3" EasingMode="EaseOut"/> </DoubleAnimation.EasingFunction> </DoubleAnimation> <DoubleAnimation Duration="0:0:0.2" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/> </Storyboard> </VisualTransition> </VisualStateGroup.Transitions> <VisualState x:Name="Closed"> <Storyboard> <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/> </Storyboard> </VisualState> <VisualState x:Name="Open"> <Storyboard> <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="X" Storyboard.TargetName="xform"/> <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="Root"/> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border Background="#052A2E31" CornerRadius="5" Margin="4,4,-4,-4"/> <Border Background="#152A2E31" CornerRadius="4" Margin="3,3,-3,-3"/> <Border Background="#252A2E31" CornerRadius="3" Margin="2,2,-2,-2"/> <Border Background="#352A2E31" CornerRadius="2" Margin="1,1,-1,-1"/> <Border Background="#FFDC000C" CornerRadius="2"/> <Border CornerRadius="2"> <TextBlock Foreground="White" MaxWidth="250" Margin="8,4,8,4" TextWrapping="Wrap" Text="{Binding (Validation.Errors)[0].ErrorContent}" UseLayoutRounding="false"/> </Border> </Grid> </ControlTemplate> <Style x:Key="OvalTextBoxStyle" TargetType="TextBox"> <Setter Property="BorderThickness" Value="1"/> <Setter Property="Background" Value="#FFFFFFFF"/> <Setter Property="Foreground" Value="#FF000000"/> <Setter Property="Padding" Value="2"/> <Setter Property="BorderBrush"> <Setter.Value> <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0"> <GradientStop Color="#FFA3AEB9" Offset="0"/> <GradientStop Color="#FF8399A9" Offset="0.375"/> <GradientStop Color="#FF718597" Offset="0.375"/> <GradientStop Color="#FF617584" Offset="1"/> </LinearGradientBrush> </Setter.Value> </Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="TextBox"> <Grid x:Name="RootElement"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="CommonStates"> <VisualState x:Name="Normal"/> <VisualState x:Name="MouseOver"> <Storyboard> <ColorAnimation Duration="0" To="#FF99C1E2" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" Storyboard.TargetName="MouseOverBorder"/> </Storyboard> </VisualState> <VisualState x:Name="Disabled"> <Storyboard> <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="DisabledVisualElement"/> </Storyboard> </VisualState> <VisualState x:Name="ReadOnly"> <Storyboard> <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="ReadOnlyVisualElement"/> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="FocusStates"> <VisualState x:Name="Focused"> <Storyboard> <DoubleAnimation Duration="0" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualElement"/> </Storyboard> </VisualState> <VisualState x:Name="Unfocused"> <Storyboard> <DoubleAnimation Duration="0" To="0" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="FocusVisualElement"/> </Storyboard> </VisualState> </VisualStateGroup> <VisualStateGroup x:Name="ValidationStates"> <VisualState x:Name="Valid"/> <VisualState x:Name="InvalidUnfocused"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationErrorElement"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <Visibility>Visible</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="InvalidFocused"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Visibility" Storyboard.TargetName="ValidationErrorElement"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <Visibility>Visible</Visibility> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsOpen" Storyboard.TargetName="validationTooltip"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <System:Boolean>True</System:Boolean> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Border x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Opacity="1" CornerRadius="20"> <Grid> <Border x:Name="ReadOnlyVisualElement" Background="#5EC9C9C9" Opacity="0" CornerRadius="20"/> <Border x:Name="MouseOverBorder" BorderBrush="Transparent" BorderThickness="1" CornerRadius="20"> <ScrollViewer x:Name="ContentElement" BorderThickness="0" IsTabStop="False" Padding="{TemplateBinding Padding}"/> </Border> </Grid> </Border> <Border x:Name="DisabledVisualElement" BorderBrush="#A5F7F7F7" BorderThickness="{TemplateBinding BorderThickness}" Background="#A5F7F7F7" IsHitTestVisible="False" Opacity="0" CornerRadius="20"/> <Border x:Name="FocusVisualElement" BorderBrush="#FF6DBDD1" BorderThickness="{TemplateBinding BorderThickness}" IsHitTestVisible="False" Margin="1" Opacity="0" CornerRadius="20"/> <Border x:Name="ValidationErrorElement" BorderBrush="#FFDB000C" BorderThickness="1" Visibility="Collapsed" CornerRadius="20"> <ToolTipService.ToolTip> <ToolTip x:Name="validationTooltip" DataContext="{Binding RelativeSource={RelativeSource TemplatedParent}}" Placement="Right" PlacementTarget="{Binding RelativeSource={RelativeSource TemplatedParent}}" Template="{StaticResource ValidationToolTipTemplate}"> <ToolTip.Triggers> <EventTrigger RoutedEvent="Canvas.Loaded"> <BeginStoryboard> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="IsHitTestVisible" Storyboard.TargetName="validationTooltip"> <DiscreteObjectKeyFrame KeyTime="0"> <DiscreteObjectKeyFrame.Value> <System:Boolean>true</System:Boolean> </DiscreteObjectKeyFrame.Value> </DiscreteObjectKeyFrame> </ObjectAnimationUsingKeyFrames> </Storyboard> </BeginStoryboard> </EventTrigger> </ToolTip.Triggers> </ToolTip> </ToolTipService.ToolTip> <Grid Background="Transparent" HorizontalAlignment="Right" Height="12" Margin="1,-4,-4,0" VerticalAlignment="Top" Width="12"> <Path Data="M 1,0 L6,0 A 2,2 90 0 1 8,2 L8,7 z" Fill="#FFDC000C" Margin="1,3,0,0"/> <Path Data="M 0,0 L2,0 L 8,6 L8,8" Fill="#ffffff" Margin="1,3,0,0"/> </Grid> </Border> </Grid> </ControlTemplate> </Setter.Value> </Setter> </Style> </UserControl.Resources>
To make my TextBox oval I wanted to add/edit the CornerRadius property to some of the Border controls in the above Template. Below are the Borders we need to visit.
Border
DisabledVisualElement
FocusVisualElement
ReadOnlyVisualElement
MouseOverBorder
Add/Modify CornerRadius property to the above Borders and set it to what ever the value you need.
But the hurdle here is to change the CornerRadius, every time we need to set a different value to all the Border control I mentioned above. To make my life easier I created a new TextBox user control with CornerRadius property.
TextBox with CornerRadius property
Create a new UserControl and inherit from TextBox as shown below
<TextBox x:Class=”SonyControls.Controls.OvalTextBox”
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:System=”clr-namespace:System;assembly=mscorlib”
mc:Ignorable=”d”
d:DesignHeight=”300″d:DesignWidth=”400″>
<TextBox.Resources>
I am not adding the entire template here. Its already depicted above.
…..
….
<Border x:Name=”Border” BorderBrush=”{TemplateBinding BorderBrush}” BorderThickness=”{TemplateBinding BorderThickness}”
Background=”{TemplateBinding Background}” Opacity=”1″ CornerRadius=“{Binding CornerRadius}“>
</TextBox.Resources>
<TextBox.Style>
<StaticResource ResourceKey=”OvalTextBoxStyle”/>
</TextBox.Style
</TextBox>
Modify the CornerRadius value with “{Binding CornerRadius}” as shown above.
In the code behind of my user control I added a dependency property and some code as shown below.
public partial class OvalTextBox : TextBox { public OvalTextBox() { InitializeComponent(); } public static DependencyProperty CornerRadiusProperty = DependencyProperty.Register("CornerRadius", typeof(CornerRadius), typeof(OvalTextBox), new PropertyMetadata(null)); public CornerRadius CornerRadius { get { return (CornerRadius)GetValue(CornerRadiusProperty); } set { SetValue(CornerRadiusProperty, value); } } public override void OnApplyTemplate() { base.OnApplyTemplate(); SetDataContext();
}
private void SetDataContext()
{
string[] bordersToUpdate = { "Border", "DisabledVisualElement", "FocusVisualElement","ReadOnlyVisualElement", "MouseOverBorder", "WatermarkVisualElement" };
foreach (string str in bordersToUpdate)
{
Border border = GetTemplateChild(str) as Border;
if (border != null)
{ border.DataContext = this; }
}
}
}
That’s it we are done with a new Textbox with CornerRadius property, you can access the new property from Code behind or through XAML.
Leave a Reply