2011-07-20 27 views
20

Escribo un control personalizado y me gustaría que el control cambie de un estado de edición a su estado normal cuando un usuario hace clic fuera del control. Estoy manejando el evento LostFocus y eso ayuda cuando un usuario hace pestañas o si hacen clic en otro control enfocable. Pero si no hacen clic en algo Focusable, no cambiará de su estado de edición. Así que tengo dos soluciones en mente:¿Cómo puede un control controlar un clic del mouse fuera de ese control?

  • caminar hasta el árbol hasta la cima más elemento cuando entra a un estado de edición y agregar un controlador para MouseDownEvent (y mango "manejado" eventos). En el controlador, quitaría el control de su estado de edición y eliminaría el controlador del elemento superior. Parece un truco, pero probablemente funcione bien.

código Ejemplo:

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; 
} 
  • Uso Mouse.PreviewMouseDownOutsideCapturedElement y agregar un controlador de mi control. En el controlador, patearía el control fuera de su estado de edición. Pero parece que no tengo el evento para disparar. ¿Cuándo se inicia el Mouse.PreviewMouseDownOutsideCapturedElement?

código Ejemplo:

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

Respuesta

12

Capture el ratón. Cuando un objeto captura el mouse, todos los eventos relacionados con el mouse se tratan como si el objeto con captura de mouse realizara el evento, incluso si el puntero del mouse está sobre otro objeto.

+2

Así que funcionó a la perfección. Todo lo que tuve que hacer fue capturar el mouse cuando entré al modo de edición, luego WPF quita automáticamente el foco del elemento cuando haces clic fuera de él. Después de perder el foco, tuve que tener cuidado con ReleaseMouseCapture(). ¡Gracias! – chrislarson

+3

La única otra cosa que tuve que tener cuidado fue cuando presionas la tecla de Windows o se inicia otra aplicación, perdería la captura del mouse sin que esto impidiera que mi control estuviera en estado de edición. Así que tuve que manejar el evento IsMouseCapturedChanged. Por ejemplo, 'private void CustomControlIsMouseCapturedChanged (object sender, DependencyPropertyChangedEventArgs e) { if ((bool) e.NewValue == false) { IsEditing = false; } } ' – chrislarson

0

Me acercaría a esto de una manera diferente: haga que el formulario que contiene el control elimine el foco del control cuando un usuario hace clic en otra parte del formulario.

Tener el control en realidad foco libre es mucho más limpio que intentar que el control "simule" el foco se pierda en ciertas situaciones, cuando en realidad no lo ha hecho. Tenga en cuenta que, a menos que el control realmente haya perdido el foco, todavía aceptará cosas como la entrada de teclado.

+0

¿Entonces está diciendo que hago que la forma sea enfocable? Porque el enfoque no se quitará automáticamente a menos que se cambie a otro elemento, ¿correcto? Por ejemplo, esto no tomará el foco del TextBox: ' \t \t \t \t ' – chrislarson

+0

@chrislarson Puede establecer otro control (por ejemplo, una etiqueta, posiblemente una sin texto) para enfocar; consulte [¿Hay alguna manera de hacer que un elemento de la IU pierda el foco?] (http://stackoverflow.com/questions/ 2664460/wpf-is-there-a-way-to-cause-an-ui-element-to-loose-focus-without-changing-the-fo) – Justin

+0

Eso está bien conmigo, aún puedo basarme si no el control está en un estado de edición por si tiene foco o no. Pero todavía necesito una manera de hacer que el control pierda el foco de manera confiable cuando un usuario hace clic fuera del control. – chrislarson

30

Solo para aclarar la respuesta proporcionada por el enfoque del ratón - que era útil, pero tenía que hacer algo de investigación más + curioseaba para conseguir algo que realmente funcionó:

yo estaba tratando de poner en práctica algo así como un cuadro combinado y necesitaba comportamiento similar: hacer que el menú desplegable desaparezca cuando se hace clic en otra cosa, sin que el control tenga conocimiento de lo que era otra cosa.

que tenían el siguiente evento de un botón desplegable:

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

El CaptureMode.SubTree significa que sólo se les acontecimientos que están fuera del control y cualquier actividad del ratón en el control se pasa a través de cosas como normales . No tiene la opción de proporcionar este Enum en CaptureMouse de UIElement, esto significa que recibirá llamadas a HandleClickOutsideOfControl INSTEAD de llamadas a cualquier control secundario u otro manejador dentro del control. Este es el caso, incluso si no se suscribe a los eventos que están utilizando, ¡la captura completa del mouse es demasiado!

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

También tendría que aferrarse a + eliminar el manejador en los puntos apropiados, pero he dejado que fuera aquí en aras de la claridad/brevedad.

Finalmente, en el controlador debe liberar la captura nuevamente.

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

Algunos controles, como TextBox, tienden a liberar caputre cuando se hace clic, por lo que tendrá que volver a conectar el controlador cada vez que se active el evento 'LostMouseCapture'. Solo mi observación. –

0

Normalmente obtengo la ventana primaria y agrego un controlador de vista previa, incluso si ya se ha manejado. A veces, cuando MouseCapture no es suficiente, esta técnica es útil:

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