WPF:选择并设置焦点到ComboBox可编辑文本框中的所有文本

3

我有一个WPF的ComboBox,它的IsEditable属性绑定到一个视图模型上,可以进行开关控制。当它被打开时,我想要将焦点放在ComboBox上,并选择编辑TextBox中的所有文本。

我不知道最好的实现方式是什么。我应该替换ControlTemplate,子类化ComboBox基类并提供所需的属性,使用附加属性,还是采用其他方法?

1个回答

6
我可以为您提供帮助。
我使用了一种模型-视图-视图模型(Model-View-ViewModel)和附加属性(Attached Property)相结合的方法。
首先,您需要了解MVVM中的消息传递系统以使其正常工作,并且要熟悉您的命令。因此,从附加属性开始,我们将设置一个IsFocused事件到我们想要聚焦并选择所有文本的组合框上。
  #region Select On Focus

  public static bool GetSelectWhenFocused(DependencyObject obj)
  {
    return (bool)obj.GetValue(SelectWhenFocusedProperty);
  }

  public static void SetSelectWhenFocused(DependencyObject obj, bool value)
  {
    obj.SetValue(SelectWhenFocusedProperty, value);
  }

  // Using a DependencyProperty as the backing store for SelectWhenFocused.  This enables animation, styling, binding, etc...
  public static read-only DependencyProperty SelectWhenFocusedProperty =
      DependencyProperty.RegisterAttached("SelectWhenFocused", typeof(bool), typeof(EditableComboBox), new UIPropertyMetadata(OnSelectOnFocusedChanged));

  public static void OnSelectOnFocusedChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
  {
    bool SetProperty = (bool)args.NewValue;     

    var comboBox = obj as ComboBox;
    if (comboBox == null) return;

    if (SetProperty)
    {
      comboBox.GotFocus += GotFocused;
      Messenger.Default.Register<ComboBox>(comboBox, Focus);
    }
    else
    {
      comboBox.GotFocus -= GotFocused;
      Messenger.Default.Unregister<ComboBox>(comboBox, Focus);
    }
  }

  public static void GotFocused(object sender, RoutedEventArgs e)
  {
    var comboBox = sender as ComboBox;
    if(comboBox == null) return;

    var textBox = comboBox.FindChild(typeof(TextBox), "PART_EditableTextBox") as TextBox;
    if (textBox == null) return;

    textBox.SelectAll();
  }

  public static void Focus(ComboBox comboBox)
  {
    if(comboBox == null) return;
    comboBox.Focus();
  }
  #endregion

这段代码展示的是当我们将附加属性SelectWhenFocused设置为true时,它将注册侦听GotFocused事件并选择其中的所有文本。

使用方法很简单:

<ComboBox
  IsEditable="True"
  ComboBoxHelper:EditableComboBox.SelectWhenFocused="True"
  x:Name="EditBox" />

现在我们需要一个按钮,当单击时,可以将焦点设置在ComboBox上。
<Button
  Command="{Binding Focus}"
  CommandParameter="{Binding ElementName=EditBox}"
  Grid.Column="1" >Focus</Button>

请注意,CommandParameter 通过其名称 EditBox 绑定到 ComboBox。这样,在执行命令时,只有此 ComboBox 获得焦点并选择所有文本。
在我的 ViewModel 中,我声明了 Focus 命令 如下:
public SimpleCommand Focus { get; set; }
public WindowVM()
{
  Focus = new SimpleCommand {ExecuteDelegate = x => Broadcast(x as ComboBox)};
}

这是我实践过的一种经过验证的技术。希望它对您的问题不是一种过度解决方案。祝好运。


谢谢,Tri。我已经实现了这个模式,但是我注意到ComboBox上没有FindChild方法。 - codekaizen
抱歉,FindChild在这里:https://dev59.com/snRB5IYBdhLWcg3wZmdz#1501391 - Tri Q Tran
谢谢,Tri。我猜测了一下实现方式,经过一番思考,看起来我已经接近成功了。然而,TextBox子元素没有被找到,原因可能是我改变了ComboBox的IsEditable属性,这使得在处理GotFocused事件时,ComboBox控件模板还没有改变,TextBox还没有被创建。有什么方法可以推迟搜索直到控件模板被应用后再进行吗? - codekaizen
已接受,因为使用附加行为是我最终采取的方法,并且似乎最适合MVVM。 - codekaizen
@TriQTran,PART_EditableTextBox是什么? - Bigeyes
@Bigeyes PART_EditableTextBox是使用组合框的默认模板时可编辑文本框的名称。 - Tri Q Tran

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