1

On Xamarin there is a Control called Entry. It supports a TextPreview which is like a default Text to show in the "background" when a TextBox is empty.

I used How can I add a hint text to WPF textbox? to get it working on a single TextBox. Now I want to make this reusable (Create a CustomControl in WPF). I also tried to forge it into a global Style here but I did't really got what i wanted. -

Long story short: How can I get this CustomControl working ?

I cannot get any further than this:

public class TextboxWithPreview : TextBox
{
    public TextboxWithPreview()
    {
        if(DesignerProperties.GetIsInDesignMode(this))
        {
            this.TextPreview = "Default TextPreview";
        }
        EventManager.RegisterClassHandler(typeof(TextboxWithPreview), TextChangedEvent, new TextChangedEventHandler(OnTextChanged));    
    }

    public static readonly DependencyProperty TextPreviewProperty = DependencyProperty.Register("TextPreview", typeof(string), typeof(TextboxWithPreview));

    private static void OnTextChanged(object sender, TextChangedEventArgs e)
    {
        //pseudo Code:
        if(string.IsNullOrEmpty(this.Text))
        {
            this.Text = TextPreview;
            this.ForeColor = Colors.Gray;
        }
    }

    public string TextPreview
    {
        get { return (string)GetValue(TextPreviewProperty); }
        set { SetValue(TextPreviewProperty, value); }
    }        
}

My thoughts about this:

Is it possible to register a second event to an existing property ? If so I'd like to attach my 2nd EventHandler to TextChanged. As soon as the Textgets cleared I want the Preview to show up.

To make things clear:

I want to create a CustomControl - no workarounds. Since it is implemented in Xamarin.Forms.Entry it is definedly possible.

Community
  • 1
  • 1
Felix D.
  • 4,811
  • 8
  • 38
  • 72
  • 1
    This is called a watermark. See this question. ^^ – Lynn Crumbling Sep 21 '16 at 12:24
  • @LynnCrumbling well ... the Watermark story is ONE solution to get it working. As I have described above I already got it working using `Syles`. The "duplicate" you provided is not about creating a custom control. – Felix D. Sep 21 '16 at 13:15
  • 1
    I see multiple answers on that question that provide a solution using a Textbox-derived control. I don't think you examined all of the answers. – Lynn Crumbling Sep 21 '16 at 13:39
  • @LynnCrumbling yeah I saw that. Unfortunately the answer is a little old (2011)... No framework is provided there (.Net 4.0 ?! or whatever). As the comments state the provided approach is not working... That means ... I still did not get the answer I need ;( - But I really appreciate your effort. – Felix D. Sep 21 '16 at 13:55

1 Answers1

1

You'll be fighting an uphill battle trying to do this by setting your existing Text property. It may be easier to place a label over the TextBox and change it's visibility.

CustomControl's are typically styled using a ControlTemplate, this template should be located in themes/Generic.xaml.

TextboxWithPreview.cs

public class TextboxWithPreview : TextBox
{
    private static DependencyPropertyKey HasTextPropertyKey = DependencyProperty.RegisterReadOnly("HasText", typeof(bool), typeof(EscapableTextBox), new PropertyMetadata());

    public static DependencyProperty HasTextProperty = HasTextPropertyKey.DependencyProperty;

    public static DependencyProperty TextPreviewProperty = DependencyProperty.Register("TextPreview", typeof(string), typeof(TextboxWithPreview));

    public bool HasText
    {
        get { return (bool)GetValue(HasTextProperty); }
        private set { SetValue(HasTextPropertyKey, value); }
    }

    public string TextPreview
    {
        get { return (string)GetValue(TextPreviewProperty); }
        set { SetValue(TextPreviewProperty, value); }
    }

    static TextboxWithPreview()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(TextboxWithPreview), new FrameworkPropertyMetadata(typeof(TextboxWithPreview)));
    }

    protected override void OnTextChanged(TextChangedEventArgs e)
    {
        base.OnTextChanged(e);

        HasText = Text.Length > 0;
    }
}

Generic.xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                    xmlns:Local="YourNamespace">

    <!-- Describes how to style a TextboxWithPreview-->
    <Style x:Key="{x:Type Local:TextboxWithPreview}" BasedOn="{StaticResource {x:Type TextBox}}" TargetType="{x:Type Local:TextboxWithPreview}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type Local:TextboxWithPreview}">
                    <Border x:Name="Border" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}" SnapsToDevicePixels="True">
                        <Grid x:Name="LayoutGrid">
                            <ScrollViewer x:Name="PART_ContentHost" Margin="2" />
                            <Label x:Name="TextPreview" Content="{Binding TextPreview, RelativeSource={RelativeSource TemplatedParent}}"
                                   FontStyle="Italic" Margin="2" Padding="2,0,0,0" />
                        </Grid>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="HasText" Value="True">
                            <Setter Property="Visibility" TargetName="TextPreview" Value="Hidden" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</ResourceDictionary>
Derrick Moeller
  • 4,808
  • 2
  • 22
  • 48
  • This worked for me, but TextboxWithPreview.cs is missing a dependency property for 'HasText'. After adding, override OnTextInput in TextboxWithPreview.cs and simply check if the TextCompositionEventArgs is null or empty. I would also suggest adding an additional trigger to Generic.xaml for IsFocused, to also hide the TextPreview label. Great solution, steered me perfectly! – Brian Mar 30 '22 at 05:06
  • @Brian I've added the `HasTextDependencyProperty` to my solution, good catch. – Derrick Moeller Mar 30 '22 at 13:54