简体   繁体   中英

Extending a control's capabilities

Let's say I want to extend all textboxes in my toolbox to do something in particular when the 'GotFocus' event is raised. Say, run a line of code that instructs them to SelectAll();

What's the most efficient way I can tack this behaviour/handling of an event to all my TextBoxes?

I'm just using TextBox as an example, as I have plans to do similar things to other controls in my WPF arsenal going forward.

You want to accomplish this using an attached behavior. Below is code that I currently use to do this and it covers a couple of quirky edge cases.

public class TextBoxBehaviors
{
    public static readonly DependencyProperty SelectAllOnFocusProperty = DependencyProperty.RegisterAttached("SelectAllOnFocus",  typeof(bool), typeof(TextBoxBehaviors), new PropertyMetadata(false, OnSelectAllOnFocusChanged));

    public static DependencyProperty GetSelectAllOnFocus(TextBox element)
    {
        return (DependencyProperty)element.GetValue(SelectAllOnFocusProperty);
    }

    public static void SetSelectAllOnFocus(TextBox element, bool value)
    {
        element.SetValue(SelectAllOnFocusProperty, value);
    }

    private static void OnSelectAllOnFocusChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var comboBox = d as ComboBox;

        if (comboBox != null)
        {
            comboBox.Loaded += ComboBox_Loaded;
            return;
        }

        var textBox = d as TextBox;

        if (textBox == null) { return; }

        if ((bool)e.OldValue)
        {
            textBox.PreviewMouseDown -= TextBox_PreviewMouseDown;
            textBox.GotFocus -= TextBox_GotFocus;
        }

        if (!(bool)e.NewValue)
            return;

        textBox.PreviewMouseDown += TextBox_PreviewMouseDown;
        textBox.GotFocus += TextBox_GotFocus;
    }

    private static void ComboBox_Loaded(object sender, RoutedEventArgs e)
    {
        var comboBox = sender as ComboBox;

        var comboText = comboBox?.Template.FindName("PART_EditableTextBox", comboBox) as TextBox;

        comboText?.SetValue(SelectAllOnFocusProperty, comboBox.GetValue(SelectAllOnFocusProperty));
    }

    private static void TextBox_GotFocus(object sender, RoutedEventArgs e)
    {
        var textBox = sender as TextBox;
        if (textBox == null) { return; }

        // We need to dispatch this in case someone is changing the text during the GotFocus
        // event.  In that case, we want to select it all after they're done.
        Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal,
                                                   (Action)(() => TextBox_DoSelectAll(textBox)));
    }

    private static void TextBox_DoSelectAll(TextBox textBox)
    {
        if (!textBox.IsFocused) return;

        textBox.CaretIndex = textBox.Text.Length;
        textBox.SelectAll();
    }


    private static void TextBox_PreviewMouseDown(object sender, MouseButtonEventArgs e)
    {
        var textBox = sender as TextBox;
        if (textBox == null) { return; }

        if (textBox.IsFocused)
            return;

        textBox.Focus();
        e.Handled = true;  // Prevent default TextBox behavior from deselecting text on mouse up
    }

}

Usage:

<TextBox beh:TextBoxBehaviors.SelectAllOnFocus="True" />

Or set it on all text boxes:

<Style TargetType="{x:Type TextBox}">
    <Setter Property="beh:TextBoxBehaviors.SelectAllOnFocus" />
</Style>

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM