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

Воспроизвести мой случай (.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. Запустите проект и установите текстовое поле в 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 ]

4 голосов
/ 02 марта 2012

Я использовал свой контракт на поддержку 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;
                    }
                }
            }
        }
    }
}
0 голосов
/ 06 апреля 2013

У нас была похожая проблема в одном из наших приложений, и мы обнаружили, что обновление до .net 4.5, по-видимому, исправило значительную часть проблем с фокусировкой WPF / WinForms нашего приложения, в том числе аналогичную этой.

Кроме того, поле _focusedChild больше не существует в версии WindowsFormsHost .net 4.5

...