Должен ли Form.ShowDialog (IWin32Window) работать с любым дескриптором окна? - PullRequest
2 голосов
/ 24 февраля 2009

При использовании System.Windows.Forms.ShowDialog(IWin32Window), могу ли я передать IWin32Window, представляющий любой дескриптор окна, и иметь ли он модальный по отношению к этому окну?

Как часть расширения Internet Explorer 7 я пытаюсь открыть модальное окно относительно вкладки Internet Explorer. Это не выбранная в данный момент вкладка, но я могу получить hwnd вкладки ОК. Однако, когда я передаю это в ShowDialog, моя форма отображается, но она не модальна в отношении чего-либо: я все еще могу делать что-то в Internet Explorer, в том числе на вкладке, которая должна быть владельцем. Моя форма показывается плавающей над окнами Internet Explorer, и она остается сверху, поэтому она не выглядит просто как обычная форма, но она не является правильно модальной.

Используя Spy ++ , я могу найти свою форму, и ее дескриптор владельца установлен правильно.

Значит ли это, что что-то пошло не так или я что-то не так делаю? Как мне сделать мою форму правильно модальной?

К вашему сведению, я использую этот класс-обертку для создания IWin32Window из hwnd (спасибо Райан! ):

/// <summary>
/// Wrapper class so that we can return an IWin32Window given a hwnd
/// </summary>
public class WindowWrapper : System.Windows.Forms.IWin32Window
{
    public WindowWrapper(IntPtr handle)
    {
        _hwnd = handle;
    }

    public IntPtr Handle
    {
        get { return _hwnd; }
    }

    private IntPtr _hwnd;
}

ОБНОВЛЕНИЕ: Использование Internet Explorer 7 & .NET 2.0

ОБНОВЛЕНИЕ: поэкспериментируя с Spy ++ и с дескрипторами, которые он выставляет, я обнаружил, что если я использую другой hwnd, тогда я могу сделать свое окно модальным для вкладки:

Я использовал вкладку hwnd, как предложено в IWebBrowser2.HWND doc , который в Spy ++ выглядит как класс TabWindowClass. У него есть дочерний элемент класса Shell DocObject View, у которого есть дочерний элемент Internet_Explorer_Server. Если я использую hwnd из Internet Explorer_Server, то он работает правильно, например, когда я щелкаю мышью по другим вкладкам, Internet Explorer реагирует нормально. Когда я щелкаю мышью по интересующей вкладке, она воспроизводит звук Windows d'Oh и ничего не делает.

Я пока не знаю, как программно получить Internet_Explorer_Server hwnd, но это должно быть возможно.

Кроме того, несмотря на то, что, играя с другими дескрипторами окон, я обычно мог сделать свою форму модальной для других приложений и диалогов. Поэтому я думаю, что ответ на мой вопрос «много, но не все ручки» ... возможно, это зависит от приложения?

ОБНОВЛЕНИЕ: Еще одно замечание: исходная причина, по которой я хотел сделать мою форму модальной для вкладки, а не для всего окна, заключается в том, что при открытии MessageBox из моей формы, передавая форму в качестве владельца, MessageBox не всегда открывается поверх моей формы. Если новая вкладка Internet Explorer была только что открыта, но не активна, тогда MessageBox будет скрыт, и эта вкладка начнет мигать. Однако, поскольку Internet Explorer был отключен при открытой модальной форме, переключиться на эту вкладку было невозможно, поэтому Internet Explorer завис. Я думал, что открытие модальной формы для вкладки решит эту проблему, но я нашел другое решение - избегать использования MessageBox: если я использую вторую форму и ShowDialog(this) из моей первой формы, тогда вторая форма правильно открывается в передний. Поэтому кажется, что Form.ShowDialog() работает лучше, чем MessageBox.Show() в некоторых случаях. Подробнее в Проблемы с модальными диалоговыми окнами и ящиками сообщений .

Ответы [ 4 ]

5 голосов
/ 24 февраля 2009

ShowDialog () делает две важные вещи. Он начинает прокачивать цикл сообщений, поэтому он действует модально с вызывающим кодом. И он отключает любые другие окна в приложении с помощью вызова API EnableWindow (false). Последнее то, что не происходит в вашем случае. Не совсем удивительно, учитывая, что окно, которое нужно отключить, не является окном WF.

Возможно, вам придется вызвать EnableWindow () самостоятельно. Обязательно включите его до закрытия диалогового окна, иначе Windows начнет искать окно другого приложения, чтобы сфокусироваться на нем.

2 голосов
/ 26 февраля 2010

Вот более краткая версия кода WindowWrapper Райана / Рори:

internal class WindowWrapper : IWin32Window
{
    public IntPtr Handle { get; private set; }
    public WindowWrapper(IntPtr hwnd) { Handle = hwnd; }
}
2 голосов
/ 24 февраля 2009

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

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

0 голосов
/ 24 февраля 2009

Я никогда не пробовал это из расширения IE, но у меня есть догадка, что IE может «не уважать» модальное окно в стиле Win32 так же, как это делает модальное окно, вызванное из Javascript с использованием window.open().

Проверяли ли вы этот код на чем-то, кроме IE, просто чтобы убедиться, что он работает так же, как и для других приложений?

...