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

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

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

示例代码:

 private void RegisterTopMostParentMouseClickEvent() { _topMostParent = this.FindLastVisualAncestor(); 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 ); 

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

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

我试图实现像combobox一样的东西并且需要类似的行为 – 当点击其他东西时让下拉消失,而没有控制权知道其他东西是什么。

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

  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(); } 

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

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

我将采用另一种方式 – 当用户单击表单的另一部分时,让包含控件的表单从控件中删除焦点。

控制实际上是松散的焦点远比在某些情况下试图使控制“模拟”焦点丢失更清晰,而实际上它没有。 请记住,除非控件确实失去了焦点,否则它仍会接受键盘输入之类的东西。