WindowsFormsHost фокусируется на активации приложения, даже активируя его другой формой wpf

Воспроизвести мой случай (.net 4.0)

  1. Создать приложение WPF (MainWindow.xaml)
  2. Добавьте пользовательский элемент управления Winform, содержащий текстовое поле (UserConrol1.cs - Winform)
  3. Поместите UserControl1 в MainWindow.xaml с помощью windowsformshost
  4. Добавьте еще одно окно WPF, которое содержит текстовое поле (wpf) для проекта (Window1.xaml)
  5. Создать и показать Window1 после MainWindow InitializeComponent

Ваш проект готов,

  1. Запустите Project и установите текстовое поле в MainWindow.xaml (в WindowsFormsHost)
  2. Деактивируйте приложение, открыв окно (проводник Windows, блокнот, winamp и т. Д.)
  3. Попробуйте написать в текстовом поле, что в окне 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;
                    }
                }
            }
        }
    }
}
Другие вопросы по тегам