初始焦点和全选行为

7

我有一个用户控件,它嵌套在充当对话框显示窗口的外壳内。我忽略了外壳窗口中的焦点,并在托管的用户控件中使用 FocusManager 将初始焦点设置为命名元素(文本框),如下所示。

这样做确实可以将光标置于命名文本框的开头;但是我想选择所有文本。

TextBoxSelectionBehavior 类(以下)通常可以做到这一点,但在这种情况下不行。是否有一种简单的 XAML 修复方法可以在初始焦点上选择命名文本框中的文本?

谢谢,
Berryl

文本框选择行为

// in app startup
TextBoxSelectionBehavior.RegisterTextboxSelectionBehavior();

/// <summary>
/// Helper to select all text in the text box on entry
/// </summary>
public static class TextBoxSelectionBehavior
{
    public static void RegisterTextboxSelectionBehavior()
    {
        EventManager.RegisterClassHandler(typeof(TextBox), UIElement.GotFocusEvent, new RoutedEventHandler(OnTextBox_GotFocus));
    }

    private static void OnTextBox_GotFocus(object sender, RoutedEventArgs e)
    {
        var tb = (sender as TextBox);
        if (tb != null)
            tb.SelectAll();
    }
}

托管的用户控件

<UserControl   
<DockPanel KeyboardNavigation.TabNavigation="Local" 
    FocusManager.FocusedElement="{Binding ElementName=tbLastName}" >

            <TextBox x:Name="tbLastName" ... />

临时解决方案

根据以下与Rachel的评论,我放弃了FocusManager而选择一些后端代码:

tbLastName.Loaded += (sender, e) => tbLastName.Focus();

虽然我仍然希望有一种声明性方法来完成简单而常见的任务...

2个回答

15
我通常使用附加属性来使文本框在获得焦点时突出显示其文本。它的使用方法如下:
<TextBox local:HighlightTextOnFocus="True" />

Attached Property的代码
public static readonly DependencyProperty HighlightTextOnFocusProperty =
    DependencyProperty.RegisterAttached("HighlightTextOnFocus", 
    typeof(bool), typeof(TextBoxProperties),
    new PropertyMetadata(false, HighlightTextOnFocusPropertyChanged));


[AttachedPropertyBrowsableForChildrenAttribute(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(TextBox))]
public static bool GetHighlightTextOnFocus(DependencyObject obj)
{
    return (bool)obj.GetValue(HighlightTextOnFocusProperty);
}

public static void SetHighlightTextOnFocus(DependencyObject obj, bool value)
{
    obj.SetValue(HighlightTextOnFocusProperty, value);
}

private static void HighlightTextOnFocusPropertyChanged(
        DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
    var sender = obj as UIElement;
    if (sender != null)
    {
        if ((bool)e.NewValue)
        {
            sender.GotKeyboardFocus += OnKeyboardFocusSelectText;
            sender.PreviewMouseLeftButtonDown += OnMouseLeftButtonDownSetFocus;
        }
        else
        {
            sender.GotKeyboardFocus -= OnKeyboardFocusSelectText;
            sender.PreviewMouseLeftButtonDown -= OnMouseLeftButtonDownSetFocus;
        }
    }
}

private static void OnKeyboardFocusSelectText(
    object sender, KeyboardFocusChangedEventArgs e)
{
    var textBox = e.OriginalSource as TextBox;
    if (textBox != null)
    {
        textBox.SelectAll();
    }
}

private static void OnMouseLeftButtonDownSetFocus(
    object sender, MouseButtonEventArgs e)
{
    TextBox tb = FindAncestor<TextBox>((DependencyObject)e.OriginalSource);

    if (tb == null)
        return;

    if (!tb.IsKeyboardFocusWithin)
    {
        tb.Focus();
        e.Handled = true;
    }
}

static T FindAncestor<T>(DependencyObject current)
    where T : DependencyObject
{
    current = VisualTreeHelper.GetParent(current);

    while (current != null)
    {
        if (current is T)
        {
            return (T)current;
        }
        current = VisualTreeHelper.GetParent(current);
    };
    return null;
}

编辑

根据下面的评论,那就只需要摆脱FocusManager.FocusedElement并在你的TextBoxLoaded事件中设置tb.Focus()tb.SelectAll()


你的代码写得不错,也和我以前使用的一样有效,但是它并没有解决我的问题。我不确定是否需要在当前操作中调用 MoveFocus。祝福。 - Berryl
我认为你代码中将obj强制转换为UIElement的那一行应该跟着一个"if(sender != null)"而不是"obj!=null"。祝好运! - Berryl
1
@Berryl 如果仅仅是想摆脱‘FocusManager.FocusedElement’,并在你的文本框的‘Loaded’事件中设置‘tb.Focus()’和‘tb.SelectAll()’,这样可行吗? - Rachel
有趣的是,'tb.Focus()'自己就能工作了,现在附加属性也能发挥作用并处理'SelectAll()'。我讨厌代码后台,但很难反驳有效的代码,所以我暂时接受它!干杯 - Berryl
@Berryl 很高兴它能够正常工作 :) 如果它是一个与视图相关的目的,比如设置焦点,我从不介意在视图后台使用代码。我会更新我的答案,包括我的最后一条评论。 - Rachel
显示剩余2条评论

4
如上所述,您可以为“Loaded”事件添加事件处理程序以设置焦点并选择所有文本:
public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        base.DataContext = new Person { FirstName = "Joe", LastName = "Smith" };

        base.Loaded += delegate
        {
            this._firstNameTextBox.Focus();
            this._firstNameTextBox.SelectAll();
        };
    }
}  

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接