Взаимодействие WPF и WindowsForms

Если Вы пытаетесь применять WPF не в абсолютно новом, а в прожившем какое-то время проекте, то наверняка столкнетесь с необходимостью взаимодействия между кусочками старого интерфейса на WindowsForms и новым интерфейсом WPF. Так и я некоторое время назад столкнулся с этой проблемой.

Задача заключалась в усовершенствовании части системы, которая включала в себя интерфейс на WindowsForms с несколькими вкладками, каждая из которых содержала UserControl. Переход на WPF следовало осуществить постепенно заменяя старые WindowsForms элементы новыми. Первым делом я создал макет бедующего приложения - окно с TabControl и две вкладки одна для WPF, другая для WindowsForms. На вкладке с WindowsForms размещен UserControl с несколькими элементами управления, занимающий всю вкладку.

<TabControl SelectedIndex>
   <TabItem Header="WPF">
      <WrapPanel>
         <Button TabIndex="1">The Button</Button>
         <TextBox TabIndex="0">The Text Box</TextBox>
      </WrapPanel>
   </TabItem>
   <TabItem Header="Windows Form" x:Name="windowsFormsTab">
      <integration:WindowsFormsHost>
         <this:TestControl x:Name="windowsFormsControl" />
      </integration:WindowsFormsHost>
   </TabItem>
</TabControl>

В старом UserControl содержалось текстовое поле, на которое должен был быть установлен фокус ввода при выборе содержащей его вкладки. В WindowsForms эта проблема решалась обработкой события VisibleChanged класса UserControl.

if (Visible)
{
   // Необходимо было также выделить все содержимое
   textBox.SelectAll();
   textBox.Focus();
}

В новом приложении этот подход работать перестал. Более того, при переключении на окна других приложений элементы WindowsForms безвозвратно теряли фокус.

Попытка обрабатывать события Selector.Selected или GotFocus элемента TabItem не приблизили к желаемой цели. Оказалось что эти события происходят слишком рано и после этого UserControl получает массу сообщений и в результате теряет фокус. Тоже самое касается и события Activated окна WPF.

Потратив кучу времени на поиск решения я не нашел ничего кроме констатации факта существования данной проблемы. Но решение все же нашлось. Решение ЖУТКОЕ, крайне ненадежное, но все же в 99% случаев приводящее к желаемому результату – отложить установку фокуса в UserControl на некоторое время.

private void SetFocuToWindowsForms()
{
    ThreadPool.QueueUserWorkItem(new WaitCallback(delegate(object o)
    {
                //Ждем пока WPF проделает
        //все что хочет с нашим UserControl

                Thread.Sleep(100);
        windowsFormsControl.Invoke(new Func<bool>(windowsFormsControl.Focus));
    }));
}

private void WpfWindow_Activated(object sender, EventArgs e)
{
    if (wfTab.IsSelected)
    {
        SetFocuToWindowsForms();
    }
}

private void windowsFormsTab_Selected(object sender, RoutedEventArgs e)
{
    SetFocuToWindowsForms();
}

Повторюсь еще раз, что этот код может не работать в некоторых ситуация, но другого решения найти пока не удалось.

Опубліковані 30-10-2009 02:14 від Dmitry Peleshenko
Зареєстрований як

Коментарі

 

RredCat said:

Привіт Дмитро.

Трішки у вашому вирішені проблеми Thread.Sleep(100); турбує - а що буде, коли гуя довше вантажитиметься? Дозвольте запропонувати своє (але якщо не працюватиме -  я не винен :) ) вирішення.

Спробуйте замість SetFocuToWindowsForms() використати наступний код:

Dispatcher.BeginInvoke( DispatcherPriority.Loaded, new Func<bool>( windowsFormsControl.Focus ) );

по теорії виклик Focus() тоді відбудеться після розміщення і відмальовування ..

Відпишіться будь-ласка чи допомогло.

ну і посилання на теорію :) :

http://msdn.microsoft.com/en-us/library/ms591206.aspx

http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcherpriority.aspx

November 3, 2009 2:35 AM
 

Dmitry Peleshenko said:

Ваша правда, Thread.Sleep(100) виглядає просто жахливо, але запропонований вами код на жаль не вирішує проблеми. Вочевидь всі дії з WindowsForms відбуваються вже після розміщення та відмальовування елементів WPF. Це добре видно якщо додати трохи трасування.

Я розглядав запропонований вами підхід і навіть трохи поекспериментував з DispatcherPriority. Випробовував також декілька підходів з використанням WindowProc в середині WindowsForms контрола. Нічого не допомогло.

November 3, 2009 1:19 PM
Анонімні коментарі деактивовані. Увійдіть або Зареєструйтесь щоб мати доступ до ресурсів Спільноти.

Календар повідомлень

<October 2009>
SMTWTFS
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

Пошук

Go

Синдикація

SkinName:iroha_Blog2