【问题标题】:Global event handler for TextBox getting focus by mouse click通过鼠标单击获得焦点的 TextBox 的全局事件处理程序
【发布时间】:2015-03-11 14:54:53
【问题描述】:

我有一种情况,我想检测应用程序中任何地方的文本框何时被用户用鼠标单击或触摸获得焦点。我通过添加这样的全局事件处理程序“解决了”这个问题:

Application.Current.MainWindow.AddHandler(UIElement.MouseLeftButtonUpEvent, new MouseButtonEventHandler(txt_MouseLeftButtonUp), true);

...

void txt_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
  if (e.OriginalSource is TextBox)
  {
    // Do somthing
  }
}

但是,如果用户单击文本框的边缘而不是中间,则宿主控件(网格、边框等)通常会接收鼠标事件并以某种方式将其传递给包含的文本框,由其处理并获得焦点。这使得上述方法徒劳无功,因为在这种情况下 TextBox 将不是 e.OriginalSource ,并且我没有发现任何方法可以确定通过单击使 TextBox 成为焦点。

例如,派生 TextBox 并覆盖 OnMouseDown 将捕获此事件,我想可以探索此路径以找到问题的解决方案,但这需要我在任何地方使用自定义 TextBox。

有人对此有很好的解决方案吗?

这是一个会触发问题的示例。通过单击文本框的边缘,网格将处理鼠标事件,并将焦点传递给文本框。

<Grid>
    <Grid HorizontalAlignment="Center"
          VerticalAlignment="Center"
          Background="Red">
      <TextBox>2323</TextBox>
    </Grid>

    <Grid Margin="200,0,0,0"
          HorizontalAlignment="Center"
          VerticalAlignment="Center"
          Background="Red" Focusable="False">
      <TextBox>2323</TextBox>
    </Grid>
   </Grid>

【问题讨论】:

  • 如果 TextBox 在没有点击的情况下获得焦点(例如,通过使用 Tab 键),您是否也要检测?
  • 好点,只能通过鼠标点击。应忽略 Tab 键焦点。
  • 请说明你想用这个做什么,这样更容易提供建议。
  • 我想在应用程序中每次单击 TextBox 时调出一个触摸键盘。只有当它被鼠标点击或触摸时。
  • 为什么要排除导致焦点的 Tab 键?

标签: c# wpf


【解决方案1】:

GotMouseCapture 事件似乎有效:

AddHandler(UIElement.GotMouseCaptureEvent,
    new MouseEventHandler(OnGotMouseCapture), true);

...

void OnGotMouseCapture(object sender, MouseEventArgs e)
{
    if (e.OriginalSource is TextBox)
    {
        // ...
    }
}

当我用鼠标单击 TextBox 元素时,会触发此事件处理程序,但是通过键盘进行的焦点更改不会触发该事件。

【讨论】:

  • 恐怕这不会捕获通过单击 TextBox 的外边缘触发的焦点操作(到目前为止,实际上托管控件接收到鼠标事件并以某种方式将其传递给文本框)。
  • @Kente 这不是“托管”控件接收点击事件并传递它,它是实际上是 TextBox 控件。您可以通过为 MouseEnter 和 MouseLeave 事件附加事件处理程序来查看这一点。 TextBox 控件似乎确实存在一个奇怪的问题,因为(在某些布局场景中)鼠标捕获区域似乎在控件边界的右侧扩展了一个像素。我只能假设这是因为 WPF 的布局系统不是基于全像素的,并且正在进行一些布局舍入。
  • @Kente 另外,默认的 TextBox 控件模板包含一个 Border 元素,其中包含一个 ScrollViewer。只有 ScrollViewer 会执行鼠标捕获并引发 GotMouseCapture 事件。由于 ScrollViewer 和包含的 Border 元素之间存在边距/填充,单击此间隙将为 TextBox 提供焦点,但 将不 引发鼠标捕获事件。我想不出任何解决此问题的方法(您不能向 ScrollViewer 添加填充,因为它会被忽略;但是您可以将其从 Border 中删除)。
  • @Kente 严格来说它并不总是控件模板中的 Border 元素,但它总是具有 的 某种装饰器 >ScrollViewer 在里面。 ScrollViewer 被命名为PART_ContentHost。
【解决方案2】:

只需为每个 TextBox 处理 GotFocus 事件。

【讨论】:

  • 这也将触发由 Tab 键聚焦的文本框。这对我不起作用。
猜你喜欢
  • 2012-07-21
  • 1970-01-01
  • 2017-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多