none
Keyboard Focus navigation problem with ElementHost hosted WPF view with WindowsFormsHost hosted controls

    Question

  • Hello.

    I have a keyboard focus problem with Windows Forms application that hosts WPF UserControls. When I press tab, the navigation works well if there are only WPF controls in the UserControl. If I add a WindowsFormsHost hosted control to this WPF UserControl, the focus is not moving away from the WindowsFormsHosted control in WPF UserControl.

    When the application is WPF application, the focus navigation works perfectly but when I add this WPF UserControl to Windows Forms application, pressing TAB doesn't work anymore.

    It would be great to get some help with this.

    Here is my code:

    public partial class Form1 : Form
    {  
    public Form1()  
    {    
    InitializeComponent();    
    ElementHost host = new ElementHost();    
    host.Dock = DockStyle.Fill;    
    host.Child = new SomeControls();    
    this.Controls.Add(host);  
    }
    }
    /// <summary>
    /// Interaction logic for SomeControls.xaml
    /// </summary>
    public partial class SomeControls : UserControl
    {  
    public SomeControls()  
    {    
    InitializeComponent();  
    }
    }
    

    <UserControl x:Class="TabAndHostTest.SomeControls"
           xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
           xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
           xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
           xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
           xmlns:forms="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"
           xmlns:my="clr-namespace:TabAndHostTest" Width="450">
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="124*" />
          <ColumnDefinition Width="388*" />
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
          <RowDefinition Height="Auto" />
        </Grid.RowDefinitions>
    
        <Label Grid.Row="0" Grid.Column="0" Content="value1" Height="28" HorizontalAlignment="Left" Name="value1" VerticalAlignment="Top" />
        <TextBox Grid.Row="0" Grid.Column="1" Height="23" HorizontalAlignment="Left" Name="textBox1" VerticalAlignment="Top" Width="257" />
    
        <Label Grid.Row="1" Content="value2" Height="28" HorizontalAlignment="Left" Name="value2" VerticalAlignment="Top" />
        <TextBox Grid.Row="1" Grid.Column="1" Height="23" HorizontalAlignment="Left" Name="textBox2" VerticalAlignment="Top" Width="257" />
    
        <Label Grid.Row="2" Grid.Column="0" Content="hostedvalue1" Height="28" HorizontalAlignment="Left" Name="hostedvalue1" VerticalAlignment="Top" />
        <WindowsFormsHost Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Left" Name="windowsFormsHost1" VerticalAlignment="Top" Width="307">
          <forms:TextBox x:Name="formsTextbox1" Height="23" Width="150" />
        </WindowsFormsHost>
    
        <Label Grid.Row="3" Grid.Column="0" Content="hostedvalue2" Height="28" HorizontalAlignment="Left" Name="hostedvalue2" VerticalAlignment="Top" />
        <WindowsFormsHost Grid.Column="1" Grid.Row="3" Height="23" HorizontalAlignment="Left" Name="windowsFormsHost2" VerticalAlignment="Top" Width="307">
          <forms:TextBox x:Name="formsupdown1" Height="23" Width="150" />
        </WindowsFormsHost>
      </Grid>
    </UserControl>
    

    Tuesday, May 31, 2011 6:22 AM

Answers

  • Hi Trainee111,

    This is one issue under situation like kind of "Winforms hosting WPF, then hosting Winforms" case.

    You could workaround this problem by adding WinformHost logic like,

    1.      Wrap the WinForms control(s) in a custom panel:

        <WindowsFormsHost Grid.Row="1" Name="_wfh" Height="100" Background="LightPink">
          <my:TabStopPanel x:Name="_tabStopPanel" >
            <my:TabStopPanel.Controls>
              <fx:Button Text="WinForm Button TabOrder 3" Width="200" Height="40"></fx:Button> 
              <fx:TextBox Width="200" Height="36" Top="50" />
            </my:TabStopPanel.Controls>
          </my:TabStopPanel>
        </WindowsFormsHost>
    
    

    2.      TabStopPanel does this:

      class TabStopPanel : Panel
      {
        internal HwndHost WpfHost { get; set; }
    
        protected override bool ProcessDialogKey(Keys keyData)
        {
          if (base.ProcessDialogKey(keyData))
            return true;
          if ((keyData & (Keys.Alt | Keys.Control)) == Keys.None)
          {
            Keys keyCode = (Keys)keyData & Keys.KeyCode;
            if (keyCode == Keys.Tab)
            {
              IKeyboardInputSink sink = WpfHost;
              return sink.KeyboardInputSite.OnNoMoreTabStops(
                new TraversalRequest((keyData & Keys.Shift) == Keys.None ? 
                  FocusNavigationDirection.Next : FocusNavigationDirection.Previous));
            }
          }
          return false;
        }
    };
    
    

    3.      Initialize it from your WPF outer control (UserControl1) with this:

    _tabStopPanel.WpfHost = _wfh;
    

     

    I composed a simple demo based on your code snippets. Please find it here, http://cid-e52a44742984b88f.office.live.com/self.aspx/.Documents/For%20Trainee111.zip

     

    Hope this helps!

    Best regards


    Yves Zhang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Trainee111 Friday, June 03, 2011 4:10 AM
    Thursday, June 02, 2011 7:48 AM

All replies

  • Hi,

    Follow the following thread

    http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/8b7e8c44-8c64-4945-8e45-17334144d5d5/


    Md. Masudur Rahman
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Tuesday, May 31, 2011 9:14 AM
  • Thank you for this link.

    I tried these other threads answers but these didn't help in this case. I cannot figure out why focus is not going out from the hosted textbox while it does it when hosting application is WPF application which hosts windows forms controls directly in WindowsFormsHost. Problem comes when I host WPF usercontrols in ElementHost and when these WPF usercontrols contain WindowsFormsHost hosted controls. I have tested this with .NET 3.5 and .NET 4 and results are same.

    Tuesday, May 31, 2011 12:30 PM
  • Hi Trainee111,

    This is one issue under situation like kind of "Winforms hosting WPF, then hosting Winforms" case.

    You could workaround this problem by adding WinformHost logic like,

    1.      Wrap the WinForms control(s) in a custom panel:

        <WindowsFormsHost Grid.Row="1" Name="_wfh" Height="100" Background="LightPink">
          <my:TabStopPanel x:Name="_tabStopPanel" >
            <my:TabStopPanel.Controls>
              <fx:Button Text="WinForm Button TabOrder 3" Width="200" Height="40"></fx:Button> 
              <fx:TextBox Width="200" Height="36" Top="50" />
            </my:TabStopPanel.Controls>
          </my:TabStopPanel>
        </WindowsFormsHost>
    
    

    2.      TabStopPanel does this:

      class TabStopPanel : Panel
      {
        internal HwndHost WpfHost { get; set; }
    
        protected override bool ProcessDialogKey(Keys keyData)
        {
          if (base.ProcessDialogKey(keyData))
            return true;
          if ((keyData & (Keys.Alt | Keys.Control)) == Keys.None)
          {
            Keys keyCode = (Keys)keyData & Keys.KeyCode;
            if (keyCode == Keys.Tab)
            {
              IKeyboardInputSink sink = WpfHost;
              return sink.KeyboardInputSite.OnNoMoreTabStops(
                new TraversalRequest((keyData & Keys.Shift) == Keys.None ? 
                  FocusNavigationDirection.Next : FocusNavigationDirection.Previous));
            }
          }
          return false;
        }
    };
    
    

    3.      Initialize it from your WPF outer control (UserControl1) with this:

    _tabStopPanel.WpfHost = _wfh;
    

     

    I composed a simple demo based on your code snippets. Please find it here, http://cid-e52a44742984b88f.office.live.com/self.aspx/.Documents/For%20Trainee111.zip

     

    Hope this helps!

    Best regards


    Yves Zhang [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by Trainee111 Friday, June 03, 2011 4:10 AM
    Thursday, June 02, 2011 7:48 AM
  • Thank you very much for this solution. My problem is now fixed.
    Friday, June 03, 2011 4:12 AM