Kasrak
Kasrak

Reputation: 1561

A custom Textbox - WPF and Xaml

I want to make a custom TextBox using XAML and a custom class with an additional property to TextBox called PosType. PosType will be rendered inside the red triangle in the side.

The TextBox should be an ordinary textbox with enough margin from left to not intercept the other text. Here is the Image showing the desired look of the textbox.

The desired text box

The Control class :

public class PosTextBox : TextBox
{
    public string PosType { get; set; }
}

**The style I wrote : (quite similar approach to what I want except here I used border and other parts may not be accurate. **

xmlns:Pro="clr-namespace:Prox.XamlControls">

<!-- Custom TextBox  -->
<Style x:Key="c1PosTextBox" TargetType="{x:Type Pro:PosTextBox}" >
    <Setter Property="OverridesDefaultStyle" Value="True" />
    <Setter Property="SnapsToDevicePixels" Value="True" />
    <Setter Property="Foreground" Value="White" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type Pro:PosTextBox}">

                <Grid>
                    <Border>
                        <Border>
                            <TextBlock Text ="{TemplateBinding Path= Pro:PosType}"></TextBlock>
                            <!--<TextBlock Text ="{TemplateBinding ElementName=Pro:PosTextBox, Path= Pro:PosType}"></TextBlock>-->
                        </Border>
                    </Border>
                    <Border Margin="5,10,5,10">
                        <ContentPresenter  Name="Content" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" TextBlock.Foreground="White"></ContentPresenter>
                    </Border>
                </Grid>

            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

How to create this custom textbox and achieve the desired look?

Edit: Please guide me to fix the minor issues based on the same approach I mentioned above.

Upvotes: 1

Views: 10615

Answers (1)

Omri Btian
Omri Btian

Reputation: 6547

You could do that using Adorners

Adorners are rendered in a different layer called AdornerLayer on top of the UIElement, Which can get you the desired affect.

public class PosTypeAdorner : Adorner
{
     private string _posText;

     // Be sure to call the base class constructor. 
     public PosTypeAdorner (UIElement adornedElement, string posText) : base(adornedElement) 
     { 
           _posText = posText;
     }

     // A common way to implement an adorner's rendering behavior is to override the OnRender 
     // method, which is called by the layout system as part of a rendering pass. 
     protected override void OnRender(DrawingContext drawingContext)
     {
          // Draw the red triangle with it's text using the drawingContext here
     }
 }

Assuming you want the text of the PosType to be bindable, you should make it as a Dependency property. Use OnApplyTemplate to attach the adorner to your text box

public class PosTextBox : TextBox
{
    public PosTextBox()
    {
    }

    public static readonly DependencyProperty PosTypeProperty =
        DependencyProperty.Register("PosType", typeof (string), typeof (PosTextBox), new PropertyMetadata(default(string)));

    public string PosType
    {
        get { return (string)GetValue(PosTypeProperty); }
        set { SetValue(PosTypeProperty, value); }
    }

    public override void OnApplyTemplate()
    {
        base.OnApplyTemplate();

        var layer = AdornerLayer.GetAdornerLayer(this);
        var posAdorner = new PosTypeAdorner(this, PosType);

        layer.Add(posAdorner);
    }
}

For more information, you can check out this links:

http://www.codeproject.com/Articles/54472/Defining-WPF-Adorners-in-XAML

http://www.nbdtech.com/Blog/archive/2010/06/21/wpf-adorners-part-1-ndash-what-are-adorners.aspx

http://www.nbdtech.com/Blog/archive/2010/06/28/wpf-adorners-part-2-ndash-placing-any-control-on-the.aspx

Good luck

Upvotes: 4

Related Questions