gpt4 book ai didi

wpf - WindowsFormsHost 窃取对激活应用程序的关注,甚至通过应用程序的其他 wpf 表单激活

转载 作者:行者123 更新时间:2023-12-05 01:22:02 25 4
gpt4 key购买 nike

重现我的案例(.net 4.0)

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

您的项目已准备就绪,

  1. 运行项目并将文本框集中在 MainWindow.xaml(在 WindowsFormsHost 中)
  2. 通过打开一个窗口(Windows 文件资源管理器、记事本、winamp 等)停用您的应用程序
  3. 尝试用鼠标单击文本框,在 Window1 窗口中的文本框中写入

并且您会看到您无法在 Window1 中将焦点设置在文本框上,因为 MainWindow Texbox(在 winformshost 中会窃取您对应用程序激活的焦点)

有什么想法吗?

主窗口.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>

主窗口.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();
}
}
}

最佳答案

我使用我的 MSDN 支持契约(Contract)来获得这个问题的答案。工程师能够从 yunusayd 的示例中重现并确认它几乎肯定是 WindowsFormsHost 中的错误。

感谢 yunus 提供最小重现样本,感谢 Microsoft 的 Keith 在不到一天的时间内解决了这个问题并提供了解决方法。

解决方法代码如下。它通过使用 .NET 反射来更改 WindowsFormsHost 中使用的私有(private)变量并禁用该错误的触发器来工作。根据与我合作的工程师的说法,这依赖于 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;
}
}
}
}
}
}

关于wpf - WindowsFormsHost 窃取对激活应用程序的关注,甚至通过应用程序的其他 wpf 表单激活,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9207462/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com