2

I try to create a TextBox with a little triangle at the top right corner. I don't really know how to achieve it. I tried to add a polygon to the textbox at this way:

<TextBox 
      x:Name="PartnerEmail"
      TextWrapping="Wrap" 
      MaxLength="50"
      Grid.Column="1"
      Grid.Row="12"
      Margin="5,1,0,1" >
      <TextBox.Style>
          <Style TargetType="TextBox" BasedOn="{StaticResource {x:Type TextBox}}">
                <Setter Property="Template">
                      <Setter.Value>
                           <ControlTemplate>
                                <Polygon Points="0,0 10,0 0,10 0,0" Margin="0,2,2,0" HorizontalAlignment="Right" Fill="#fcba03" FlowDirection="RightToLeft"/>
                           </ControlTemplate>
                      </Setter.Value>
                </Setter>
           </Style>
      </TextBox.Style>

But obviously it's not gonna work because I override the default template, so after this, all I have is a polygon and the textbox disappears. Can anyone have a good solution for this?

Stacy Dudovitz
  • 952
  • 9
  • 11
KoB81
  • 47
  • 7

3 Answers3

1

You are on the right track, but are working a bit too hard...

The thing to keep in mind about UI elements in WPF is that they work in layers. Think of elements as a composite of smaller items that you want to stack in a 3-D space. You aren't just working in a 2 dimensional drawing space anymore like a GDI rendering space of WinForms.

So lets logically think about what you want to do here. Lets try to achieve several goals in our solution:

  • Lets make a control template that will allow us to reuse our newly minted control.
  • Lets make the control completely portable in 3 dimensional space i.e. no use of raster images that will distort if we resize our control - lets stick to geometry only for drawing.

  • Lets make it easy to decide how large to make the triangle in the corner.

  • Lets decide to allow easy modifications for later, such as triangle placement (you want to change its location), hit testing (should it be part of the text surface or the border?), color (again, border or text?), etc.

Ok, to solve this, I alluded to the idea of objects in layers. Lets divide our drawing surface into a grid:

enter image description here

That means we want to use a Grid control. We want to define two rows and two columns, and we want to TextBox to cover all 4 cells. We will make sure to set the Rowspan and Columnspan to fill the grid.

We will then add a 2nd item, our Polyline triangle to row 1 column 1, and add it after the text box. That way it's Z-order will be on top.

Here then is the control template:

<Window.Resources>
    <Style x:Key="TriangleTextBox" TargetType="{x:Type TextBox}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type TextBox}">
                    <Grid>
                        <Grid.RowDefinitions>
                            <RowDefinition Height="10"/>
                            <RowDefinition Height="6*"/>
                        </Grid.RowDefinitions>
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="6*" />
                            <ColumnDefinition Width="10" />
                        </Grid.ColumnDefinitions>
                        <TextBox Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Grid.ColumnSpan="2" Margin="0,0,0,0" Text="{TemplateBinding Text}" BorderThickness="1"/>
                        <Polygon Grid.Row="0" Grid.Column="1" Points="0,0 10,0 0,10 0,0" Fill="Black" FlowDirection="RightToLeft"/>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Window.Resources>

Note that we set the key to "TriangleTextBox".

Now its just a simple matter of using our control template as follows:

<Grid>
    <TextBox Style="{StaticResource ResourceKey=TriangleTextBox}" Width="100" Height="20"/>
</Grid>

And there you have it:

enter image description here

You can expand on this from there.

Stacy Dudovitz
  • 952
  • 9
  • 11
0

You are essentially replace the entire textbox by nothing but a triangle. You should copy the base template, and modify it from there:

    <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}">
                    <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"/>-->
                        <Grid>
                            <Polygon Points="0,0 10,0 0,10 0,0" Margin="0,2,2,0" HorizontalAlignment="Right" Fill="#fcba03" FlowDirection="RightToLeft"/>
                            <ScrollViewer x:Name="PART_ContentHost" Focusable="false" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden"/>
                        </Grid>
                    </Border>
                    <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}"/>
                        </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>

As for the template itself, you get it from microsoft, or via visual studio.

Xiaoy312
  • 14,292
  • 1
  • 32
  • 44
0

Create a user (composite) control which would have the polygon (drawn last) to overlay a textbox in the corner as needed. Usage of a Canvas control for specific placement or within a Grid for general placement in the control.


Here is where I had to put a search icon over a text field in a grid. I set the ZIndex as needed.

enter image description here

Code

<TextBox Grid.ColumnSpan="2" 
         Panel.ZIndex="0" 
         HorizontalAlignment="Stretch" 
         VerticalAlignment="Stretch"  />

<Image Grid.Column="1" Source="../Assets/Search.png" 
       Panel.ZIndex="1"
       HorizontalAlignment="Stretch" 
       VerticalAlignment="Stretch"  
       Stretch="Uniform"/>
ΩmegaMan
  • 29,542
  • 12
  • 100
  • 122