2

我正在寻找一种通用方法来支持我的 WPF TextBox 控件的键盘楔形扫描。

(当谈到更高级的 WPF 功能时,我真的是一个新手,所以在我投入大量时间进行研究之前,我想问问我是否朝着正确的方向前进。)

我想要做的是向我的 TextBoxes 添加一个附加属性(或其他东西),这将导致它读取所有输入到框中,然后使用扫描的输入调用自定义“ScanCompleted”命令。

如果附加属性不适合此,那么有没有办法在文本框上获取此命令,而无需降低我自己的自定义“ScanableTextBox”?

(注意:扫描(而不是输入数据)的标准是以暂停键 (#19) 开始,以返回键 (#13) 结束。)

4

1 回答 1

4

我认为这可能可以通过附加属性(行为)来完成,但是简单地继承TextBox并覆盖OnTextChangedOnKeyDownOnKeyUp类似方法来添加自定义功能会更简单、更直接。

您为什么不想以这种方式创建自己的控件?

更新:附加行为

如果您真的不想要派生控件,请使用以下附加行为来完成此操作(以下说明):

  public class ScanReading
  {
    private static readonly IDictionary<TextBox, ScanInfo> TrackedTextBoxes = new Dictionary<TextBox, ScanInfo>();

    public static readonly DependencyProperty ScanCompletedCommandProperty =
      DependencyProperty.RegisterAttached("ScanCompletedCommand", typeof (ICommand), typeof (ScanReading), 
      new PropertyMetadata(default(ICommand), OnScanCompletedCommandChanged));

    public static void SetScanCompletedCommand(TextBox textBox, ICommand value)
    {
      textBox.SetValue(ScanCompletedCommandProperty, value);
    }

    public static ICommand GetScanCompletedCommand(TextBox textBox)
    {
      return (ICommand) textBox.GetValue(ScanCompletedCommandProperty);
    }

    private static void OnScanCompletedCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
      var textBox = d as TextBox;
      if (textBox == null)
        return;

      var command = (ICommand) e.NewValue;

      if (command == null)
      {
        textBox.Unloaded -= OnTextBoxUnloaded;
        textBox.KeyUp -= OnTextBoxKeyUp;
        TrackedTextBoxes.Remove(textBox);
      }
      else
      {
        textBox.Unloaded += OnTextBoxUnloaded;
        TrackedTextBoxes.Add(textBox, new ScanInfo(command));

        textBox.KeyUp += OnTextBoxKeyUp;
      }
    }

    static void OnTextBoxKeyUp(object sender, KeyEventArgs e)
    {
      var textBox = (TextBox) sender;

      var scanInfo = TrackedTextBoxes[textBox];
      if (scanInfo.IsTracking)
      {
        if (e.Key == Key.Return)
        {
          scanInfo.ScanCompletedCommand.Execute(textBox.Text);
          scanInfo.IsTracking = false;
        }
      }
      else if (string.IsNullOrEmpty(textBox.Text) && e.Key == Key.Pause)
      {
        TrackedTextBoxes[textBox].IsTracking = true;
      }
    }

    static void OnTextBoxUnloaded(object sender, RoutedEventArgs e)
    {
      var textBox = (TextBox) sender;
      textBox.KeyUp -= OnTextBoxKeyUp;
      textBox.Unloaded -= OnTextBoxUnloaded;
      TrackedTextBoxes.Remove(textBox);
    }
  }

  public class ScanInfo
  {
    public ScanInfo(ICommand scanCompletedCommand)
    {
      ScanCompletedCommand = scanCompletedCommand;
    }

    public bool IsTracking { get; set; }
    public ICommand ScanCompletedCommand { get; private set; }
  }

通过声明TextBox这样的方式来使用它(local您的附加属性的命名空间在哪里,并且ScanCompletedICommand您的视图模型上):

<TextBox local:ScanReading.ScanCompletedCommand="{Binding ScanCompleted}" />

现在,当设置此属性时,我们将TextBox与关联的 一起添加到静态集合中ICommand

每次按下一个键,我们检查它是否是Pause键。如果是,并且如果TextBox是空的,我们设置一个标志true来开始寻找Enter密钥。

现在每次按下一个键,我们检查它是否是Enter键。如果是,我们执行命令,传入TextBox.Text值,并将标志重置falseTextBox.

我们还为事件添加了一个处理程序TextBox.Unloaded来清理我们的事件订阅并TextBox从静态列表中删除。

于 2012-04-30T20:51:28.030 回答