WindowsFormsHost фокусируется на активации приложения, даже активируя его другой формой wpf
Воспроизвести мой случай (.net 4.0)
- Создать приложение WPF (MainWindow.xaml)
- Добавьте пользовательский элемент управления Winform, содержащий текстовое поле (UserConrol1.cs - Winform)
- Поместите UserControl1 в MainWindow.xaml с помощью windowsformshost
- Добавьте еще одно окно WPF, которое содержит текстовое поле (wpf) для проекта (Window1.xaml)
- Создать и показать Window1 после MainWindow InitializeComponent
Ваш проект готов,
- Запустите Project и установите текстовое поле в MainWindow.xaml (в WindowsFormsHost)
- Деактивируйте приложение, открыв окно (проводник Windows, блокнот, winamp и т. Д.)
- Попробуйте написать в текстовом поле, что в окне 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 ответа
У нас была похожая проблема в одном из наших приложений, и мы обнаружили, что обновление до.net 4.5, по-видимому, исправило значительную часть проблем фокуса WPF/WinForms нашего приложения, в том числе и аналогичное этому.
Кроме того, поле _focusedChild больше не существует в версии WindowsFormsHost.net 4.5.
Я использовал свой контракт на поддержку MSDN, чтобы получить ответ на эту проблему. Инженер смог воспроизвести образец юнусайда и подтвердил, что это почти наверняка ошибка в WindowsFormsHost.
Спасибо Юнусу за минимальный пример репродукции и Китаю из Microsoft за решение этой проблемы и решение этой проблемы менее чем за один день.
Обходной код выглядит следующим образом. Он работает с использованием отражения.NET для изменения закрытой переменной, используемой в WindowsFormsHost, и отключения триггера для ошибки. По словам инженера, с которым я работал, это зависит от внутренних компонентов WPF, но он поговорил с членами команды разработчиков продукта, и его следует использовать безопасно. Конечно, нет никаких гарантий отсутствия побочных эффектов, но до сих пор я не обнаружил никаких проблем при тестировании с несколькими WindowsFormsHosts в нескольких окнах WPF (возможно, вложение было бы сложнее). Я изменил оригинальный обходной путь, чтобы работать в общем случае с несколькими окнами. Вы можете также легко жестко кодировать ссылки на определенные окна и именованные элементы управления WindowsFormsHost в событии Application_Deactivation и пропускать всю схему "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;
}
}
}
}
}
}