2011-03-02 22 views
12

Me he encontrado con problemas al alojar un formulario de WinForms dentro de un WindowsFormsHost y la pestaña de navegación. Para resolver he hecho este sencillo ejemplo:WPF que aloja un WinForm, Tab. Problemas de navegación

  • Creado WPF Window
  • Creado WinForms Form (punto de aplicación inicial) con dos TextBox en él
  • ventana de WPF: Añadido WindowsFormsHost a ella
  • ventana
  • WPF : Añadido OnLoaded manejador
  • ventana
  • WPF: Añadido Textbox encuentra debajo del WindowsFormsHost

En el controlador OnLoaded que tengo:

System.Windows.Forms.Form f = new WinFormsForm(); 
f.TopLevel = false; 
f.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None; 
this.windowsFormsHost1.Child = f; 

Cuando ahora ejecutar la aplicación:

  • Nada se centra (OK)
  • hago clic en el primer TextBox en el WindowsFormsHost, se enfoca (ok)
  • Presiono la pestaña, el foco va al 2nd TextBox en el WindowsFormsHost (ok)
  • Presiono la pestaña nuevamente, el foco vuelve al 1er TextBox en el WindowsFormsHost (no bien; debería haber dejado WindowsFormsHost y dado el enfoque al cuadro de texto en la parte inferior de la ventana de WPF)
  • hago clic en el cuadro de texto en el WPF (coloca después y bajo la WindowsFormsHost), se pone el foco (OK)
  • presiono pestaña , el foco va al 1er cuadro de texto en WindowsFormsHost - como debe ir al principio después del final. Así que esto es aceptable también
  • hacer clic en el cuadro de texto WPF de nuevo y presiona SHIFT + TAB, el foco va a segundo cuadro de texto en WindowsFormsHost (OK)
  • presiono pestaña, el foco va a primera caja de texto en WindowsFormsHost (va al principio de la FMH) (no bien)

como hago para quitar el foco comportarse como si tuviera sólo los controles de un tipo? Es decir, un orden de tabulación de WFH-1st-Textbox, WFH-2nd-Textbox, WPF-Textbox en este caso.

+0

En el proyecto real que me condujo a este problema minimizado, la situación es incluso un poco diferente. Allí, la tecla de tabulación cambia entre todos los controles de WPF (incluido WindowsFormsHost). Pero una pestaña-prensa en WindowsFormsHost no va a uno de los otros controles de WinForms dentro de WindowsFormsHost, simplemente deja que WindowsFormsHost continúe con el siguiente control de WPF. – ZoolWay

Respuesta

7

De acuerdo con los artículos que he encontrado, parece que no es posible lograrlo. De acuerdo con MSDN Blog Entry (sección Hwnds), los controles de Windows Forms siempre están encima de los controles WPF en la jerarquía. El MSDN article (sección Adquirir mensajes del bucle de mensajes de WPF) indica que los eventos que se producen en un elemento de WindowsFormsHost se procesarán antes de que WPF los conozca.

Supongo que el evento disparado presionando la tecla TAB es procesado por el elemento WindowsFormsHost (lo que resulta en el foco del otro cuadro de texto). En la ventana de WPF adjunta, el evento nunca se encontrará porque "ya se ha procesado". Por otro lado, cuando presiona la tecla TAB en el cuadro de texto de WPF, WPF maneja el evento en sí y la cadena de control se procesa normalmente.Con esto, el foco llegará a un cuadro de texto en el elemento WindowsFormsHost y desde allí no puede abandonarlo usando el teclado.

Sé que esto no ayudará a su problema actual, pero espero que explique algunas cosas.


ADENDA Si no es dependiente en el uso de un control de formulario, puede cambiar en un WinForms fácil de control con los mismos elementos de control en el mismo. Después de que cambie la inicialización del elemento WindowsFormsHost de la siguiente manera:

System.Windows.Forms.UserControl control = new WinFormUC(); 
windowsFormsHost1.Child = control; 

La clase WinFormUC es mi WinForms fácil de control que contiene los cuadros de texto mencionados. En mi prueba, al presionar la tecla TAB, los recuadros de texto se enfocaron uno tras otro, independientemente de si se trata de un Winforms o un cuadro de texto WPF.

+0

¿Puede haber una manera de enseñar el primer y último control en la parte WinForms para comportarse de manera diferente? ¿Te gusta "liberar el foco para un mayor control"? – ZoolWay

+0

Tu apéndice parece interesante. En resumen: ¿Funciona como debería si incorporaste un UserControl en lugar de un formulario? – ZoolWay

+0

Correcto. Al menos para mi pequeño ejemplo. – Osiris76

4

Puede hacer esto con un pequeño truco. Supongamos que su formulario de WPF con el anfitrión tiene el siguiente aspecto:

<StackPanel> 
    <TextBox LostFocus="TextBox_LostFocus" /> 
    <wf:WindowsFormsHost Name="host" /> 
    <TextBox/> 
</StackPanel> 

En el evento LostFocus del primer cuadro de texto se establece el foco al primer botón de la WinForm. De esta manera, usted asegura que el enfoque siempre comienza en el primer botón.

private void TextBox_LostFocus(object sender, RoutedEventArgs e) 
{ 
    Form1 f = (Form1)host.Child; 
    f.EnableTabStops(true); 
} 

En el WinForm que tiene que codificar EnableTabStops de la siguiente manera:

public void EnableTabStops(bool IsEnabled) 
{ 
    this.button1.TabStop = IsEnabled; 
    this.button2.TabStop = IsEnabled; 
    if (IsEnabled) button1.Focus(); 
} 

A continuación, la ficha a través de los botones del WinForm. Al entrar en el último botón de la WinForm deshabilitar/eliminar todos los tabuladores para que la próxima ficha sólo puede saltar a su forma WPF padres, así:

private void button2_Enter(object sender, EventArgs e) 
{ 
    EnableTabStops(false); 
} 

Esto debería hacer el trabajo.

+0

Lo probaré el lunes. – ZoolWay

4

Ésta es la manera que he implementado este:

creé un control que hereda de WindowsFormsHost

public class MyWpfControl: WindowsFormsHost 
{ 
    private MyWindowsFormsControl _winControl = new MyWindowsFormsControl(); 

    public MyWpfControl() 
    { 
     _winControl.KeyDown += _winControl_KeyDown; 
    } 

    void _winControl_KeyDown(object sender, KeyEventArgs e) 
    { 
     if (e.KeyCode == Keys.Tab && e.Shift) 
     { 
      MoveFocus(new TraversalRequest(FocusNavigationDirection.Previous));       
     } 
     else if (e.KeyCode == Keys.Tab) 
     { 
      MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));    
     }     
    } 
} 

funcionaba perfectamente para mí

utilizando el mismo enfoque también puede hacer que su control de ventanas tiene los enlaces de datos wpf necesarios:

public static readonly RoutedEvent SelectionChangedEvent = EventManager.RegisterRoutedEvent("SelectionChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MyWpfControl)); 

    public event RoutedEventHandler SelectionChanged 
    { 
     add { AddHandler(SelectionChangedEvent, value); } 
     remove { RemoveHandler(SelectionChangedEvent, value); } 
    } 

    void RaiseSelectionChangedEvent() 
    { 
     var newEventArgs = new RoutedEventArgs(SelectionChangedEvent); 
     RaiseEvent(newEventArgs); 
    } 

    private void InitDependencyProperties() 
    { 
     _winControl.EditValueChanged += (sender, e) => 
     { 
      SetValue(SelectedValueProperty, _winControl.EditValue); 

      if (!_disabledSelectionChangedEvent) 
      { 
       RaiseSelectionChangedEvent(); 
      } 
     }; 

    } 

public static readonly DependencyProperty SelectedValueProperty = DependencyProperty.Register("SelectedValue", typeof(string), typeof(MyWpfControl), 
    new PropertyMetadata("", 
    (d, e) => 
    { 
     var myControl = d as MyWpfControl; 
     if (myControl != null && myControl._brokersCombo != null) 
     { 
      var val = myControl.GetValue(e.Property) ?? string.Empty; 
      myControl._winControl.EditValue = val;        
     } 
    }, null)); 

Aquí está el XAML:

<u:MyWpfControl x:Name="myWpfControl" Margin="5,0,0,0" DataSource="{Binding BindingData,  UpdateSourceTrigger=PropertyChanged}" SelectedValue="{Binding SelectedPropertyNameOnViewModel, Mode=TwoWay}"> 
</u:MyWpfControl> 
+0

Esto parece interesante, ¡tendré que intentarlo! – ZoolWay

Cuestiones relacionadas