控件如何在该控件外部处理鼠标单击?

时间:2011-07-20 12:20:08

标签: c# wpf custom-controls mouseevent

我正在编写一个自定义控件,当用户点击控件时,我希望控件从编辑状态切换到正常状态。我正在处理LostFocus事件,这有助于当用户选中时或者他们点击另一个可聚焦的控件时。但如果他们没有点击Focusable,它就不会切换出它的编辑状态。所以我有两个解决方案:

  • 当树进入编辑状态时,将树向上移动到最顶层元素,并为MouseDownEvent添加处理程序(并处理“已处理”事件)。在处理程序中,我将控件从其编辑状态中踢出,并从最顶层的元素中删除处理程序。这似乎有点像黑客,但它可能会运作良好。

示例代码:

private void RegisterTopMostParentMouseClickEvent()
{
   _topMostParent = this.FindLastVisualAncestor<FrameworkElement>();
   if ( _topMostParent == null )
      return;
   _topMostParent.AddHandler( Mouse.MouseDownEvent, new MouseButtonEventHandler( CustomControlMouseDownEvent ), true );
}

private void UnRegisterTopMostParentMouseClickEvent()
{
   if ( _topMostParent == null )
      return;
   _topMostParent.RemoveHandler( Mouse.MouseDownEvent, new MouseButtonEventHandler( CustomControlMouseDownEvent ) );
   _topMostParent = null;
}
  • 使用Mouse.PreviewMouseDownOutsideCapturedElement并为我的控件添加处理程序。在处理程序中,我将控件从其编辑状态中踢出。但我似乎没有让事件发生。 Mouse.PreviewMouseDownOutsideCapturedElement什么时候开始?

示例代码:

AddHandler( Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler( EditableTextBlockPreviewMouseDownOutsideCapturedElementEvent ), true );

4 个答案:

答案 0 :(得分:35)

只是为了澄清关于鼠标焦点的答案 - 它很有用,但我不得不进一步挖掘+捣乱以获得实际工作的东西:

我试图实现像组合框这样的东西并且需要类似的行为 - 当点击其他东西时,让下拉消失,而没有控件知道其他东西是什么。

我有一个下拉按钮的以下事件:

    private void ClickButton(object sender, RoutedEventArgs routedEventArgs)
    {
        //do stuff (eg activate drop down)
        Mouse.Capture(this, CaptureMode.SubTree);
        AddHandler();
    }

CaptureMode.SubTree意味着您只能获取控件之外的事件,并且控件中的任何鼠标活动都会正常传递给事物。你没有选择在UIElement的CaptureMouse中提供这个枚举,这意味着你将调用HandleClickOutsideOfControl INSTEAD来调用控件中的任何子控件或其他处理程序。即使您没有订阅他们正在使用的事件也是如此 - 完全鼠标捕获有点太多了!

    private void AddHandler()
    {
        AddHandler(Mouse.PreviewMouseDownOutsideCapturedElementEvent, new MouseButtonEventHandler(HandleClickOutsideOfControl), true);
    }

您还需要在适当的位置继续+删除处理程序,但为了清晰/简洁起见,我已将其留在此处。

最后在处理程序中,您需要再次释放捕获。

    private void HandleClickOutsideOfControl(object sender, MouseButtonEventArgs e)
    {
        //do stuff (eg close drop down)
        ReleaseMouseCapture();
    }

答案 1 :(得分:13)

捕获鼠标。 当一个对象捕获鼠标时,所有与鼠标相关的事件都会被视为具有鼠标捕获的对象执行该事件,即使鼠标指针位于另一个对象上也是如此。

答案 2 :(得分:1)

我通常会获得父窗口并添加预览处理程序,即使已经处理过。有时当MouseCapture不够时,这种技术很方便:

Window.GetWindow(this).AddHandler
(
    UIElement.MouseDownEvent,
    (MouseButtonEventHandler)TextBox_PreviewMouseDown,
    true
);

答案 3 :(得分:0)

我会以不同的方式处理 - 当用户点击表单的其他部分时,让包含控件的表单从控件中移除焦点。

让控件实际松散焦点比在某些情况下试图控制“模拟”焦点丢失要清晰得多,实际上它没有。请记住,除非控件确实失去焦点,否则它仍会接受键盘输入等内容。