WindowsFormsHost窃取的重点是激活应用程序,甚至通过应用程序的其他wpf形式激活

时间:2012-02-09 08:24:14

标签: wpf windowsformshost focus-stealing

重现我的情况(.net 4.0)

  1. 创建WPF应用程序(MainWindow.xaml)
  2. 添加包含文本框的Winform用户控件(UserConrol1.cs - Winform)
  3. 使用windowsformshost将UserControl1放入MainWindow.xaml
  4. 将另一个包含文本框(wpf)的WPF窗口添加到项目(Window1.xaml)
  5. 在MainWindow InitializeComponent
  6. 之后创建并显示Window1

    您的项目已准备就绪,

    1. 运行Project并将文本框设置为主要在MainWindow.xaml(在WindowsFormsHost中)
    2. 通过打开一个窗口(Windows文件浏览器,记事本,winamp等)来停用您的应用程序。
    3. 尝试通过单击带有鼠标的文本框
    4. 在Window1窗口中的文本框中书写

      你会看到你无法在Window1中设置文本框的焦点,因为MainWindow Texbox(在winformshost中会窃取你关注你的应用程序的激活)

      有什么想法吗?

      MainWindow.xaml

      <Window x:Class="WinFormsHostFocusProblem.MainWindow"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:local="clr-namespace:WinFormsHostFocusProblem"
              xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
              Title="MainWindow" Height="350" Width="525">
          <Grid>
            <my:WindowsFormsHost  Focusable="False"  >
               <local:UserControl1>
      
               </local:UserControl1>
            </my:WindowsFormsHost>
      
         </Grid>
      </Window>
      

      MainWindow.xaml.cs

      namespace WinFormsHostFocusProblem
      {
         public partial class MainWindow : Window
         {
            public MainWindow()
            {
               InitializeComponent();
               Window1 window1 = new Window1();
               window1.Show();
            }
         }
      }
      

      Window1.xaml

      <Window x:Class="WinFormsHostFocusProblem.Window1"
              xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:local="clr-namespace:WinFormsHostFocusProblem"
              xmlns:my="clr-namespace:System.Windows.Forms.Integration;assembly=WindowsFormsIntegration"
              SizeToContent="WidthAndHeight" 
              ResizeMode="NoResize"
      
              Topmost="True"
              Title="Window1" Height="300" Width="300" Background="Red">
          <Grid>
            <TextBox Height="25">asd</TextBox>
         </Grid>
      </Window>
      

      Window1.xaml.cs

      namespace WinFormsHostFocusProblem
      {
         public partial class Window1 : Window
         {
            public Window1()
            {
               InitializeComponent();
            }
         }
      }
      

2 个答案:

答案 0 :(得分:4)

我使用我的MSDN支持合同来解决这个问题。工程师能够从yunusayd的样本中重新编写并确认它几乎肯定是WindowsFormsHost中的一个错误。

感谢yunus提供最小的repro示例和微软的Keith解决问题并在不到一天的时间内提供解决方法。

随后是变通方法代码。它的工作原理是使用.NET反射来更改WindowsFormsHost中使用的私有变量,并禁用该错误的触发器。据我工作的工程师说,这依赖于WPF内部,但他与产品团队成员交谈,应该可以安全使用。当然,并不能保证缺少副作用,但到目前为止,我在多个WPF窗口中使用多个WindowsFormsHosts进行测试时没有发现任何问题(可能嵌套会比较棘手)。我修改了原始的解决方法,以便通常使用多个窗口。您可以轻松地硬编码对特定窗口的引用,并在Application_Deactivated事件中命名为WindowsFormsHost控件,并跳过整个“LastActive”方案和扩展方法。

// App.xaml.cs: you must hook up to Application.Deactivated
void Application_Deactivated(object sender, EventArgs e)
{
    foreach (Window w in windows)
    {
        foreach (var host in UI.DependencyObjectExtension.AllLogicalChildren(w).
                     Where(c => c is WindowsFormsHost))
        {
            FIELD_FOCUSED_CHILD.SetValue(host, null);
        }
    }
}


public readonly static FieldInfo FIELD_FOCUSED_CHILD = typeof(System.Windows.Forms.Integration.WindowsFormsHost).
    GetField("_focusedChild", BindingFlags.NonPublic | BindingFlags.Instance);

public static class DependencyObjectExtension
{
    /// <summary>
    /// Returns a collection of o's logical children, recursively.
    /// </summary>
    /// <param name="o"></param>
    /// <returns></returns>
    public static IEnumerable<DependencyObject> AllLogicalChildren(this DependencyObject o)
    {
        foreach (var child in LogicalTreeHelper.GetChildren(o))
        {
            if (child is DependencyObject)
            {
                yield return (DependencyObject)child;

                if (child is DependencyObject)
                {
                    foreach (var innerChild in AllLogicalChildren((DependencyObject)child))
                    {
                        yield return innerChild;
                    }
                }
            }
        }
    }
}

答案 1 :(得分:0)

我们在其中一个应用程序中遇到了类似问题,发现升级到.net 4.5似乎修复了我们应用程序的WPF / WinForms焦点问题的很大一部分,包括与此类似的问题。

此外,WindowsFormHost的.net 4.5版本中不再存在_focusedChild字段