Как получить самое верхнее окно, если оно модальное и неактивное

Я хочу запретить пользователям запускать мое приложение несколько раз на одном компьютере, поэтому я использовал решение из этого потока: Как правильно создать приложение с одним экземпляром?

Это работает нормально, но у меня проблема с отображением моего приложения при открытии модального окна (например, с view.ShowDialog();). Это сценарий:

  1. Пользователь запускает мое приложение и открывает модальное окно.
  2. Затем он пытается снова запустить мое приложение, код в процедуре запуска этого второго экземпляра приложения находит другое запущенное приложение и транслирует ему сообщение WM_SHOWME, чтобы показать себя. Затем второй экземпляр приложения завершается.
  3. Первое приложение получает сообщение WM_SHOWME (используя решение из Как обрабатывать сообщения WndProc в WPF?). Теперь он должен вывести самое верхнее окно на передний план, и это мой вопрос - как я могу получить самое верхнее окно моего приложения, если самое верхнее окно является модальным и даже не активным? Я пробовал использовать решение из Обратиться к активному окну в WPF?, но, конечно, мои окна не активны, поэтому это не так. т работать.

PS - когда приложение запущено и открывается модальное окно, и когда я нахожу курсор на значок на панели задач, я вижу два окна - главное окно и модальное окно. Я могу щелкнуть по главному окну (которое, конечно, отключено, потому что модальное окно находится поверх него), а также могу щелкнуть по модальному окну. Мое решение работает так же, как если бы я щелкнул по главному окну, но я хочу, чтобы оно могло активировать самое верхнее окно, которое в данном случае является модальным.

Итак, есть идеи, как вывести самое верхнее модальное окно (или главное окно, если модальные окна не отображаются) на передний план?


person sventevit    schedule 20.05.2017    source источник
comment
Хм, это намеренно, что на панели задач отображаются как значок для главного окна, так и модальное окно (диалоговое окно)? Похоже, диалог не принадлежит главному окну. Если вы сделаете диалог принадлежащим главному окну, диалог никогда не будет перекрываться главным окном. Это также приводит к тому, что при переносе главного окна на передний план модальное окно также выводится на передний план. (Проверьте свойство Owner модального окна. Оно должно быть главным окном.)   -  person    schedule 20.05.2017
comment
@elgonzo - вы правы, забыл установить свойство Owner, спасибо! Если вы разместите свой комментарий в качестве ответа, я приму его.   -  person sventevit    schedule 20.05.2017
comment
Это сделано... :)   -  person    schedule 20.05.2017


Ответы (2)


Поведение, описанное в вопросе, означает, что главное окно не владеет диалоговым окном.

Обратите внимание, что когда диалог принадлежит (главному) окну, тогда окно не может закрывать диалог (диалог обычно всегда остается в верхней части окна). Это также приводит к тому, что при перемещении окна на передний план диалоговое окно также выводится на передний план в верхней части окна, что аккуратно решает вашу проблему.

Установить владельца для вашего диалога (модального окна) довольно просто. Просто установите его Владелец в главном окне перед отображением диалогового окна, как в этом примере:

Window modalWindow = ... create modal window instance
modalWindow.Owner = mainWindow;
modalWindow.ShowDialog();

(Примечание: если также желательно, чтобы на панели задач отображался только значок / эскиз главного окна, тогда для свойства ShowInTaskbar модального окна должно быть установлено значение false.)

person Community    schedule 20.05.2017
comment
Как было сказано ранее - ваше решение работает. Просто придирка - даже если вы установите свойство Owner, вы все равно сможете видеть как главное окно, так и диалоговое окно, когда вы наводите курсор на значок на панели задач. Но id на самом деле не имеет значения, в каком окне вы щелкнете, модальное всегда находится наверху. - person sventevit; 20.05.2017
comment
@sventevit, ха-ха, ты прав. Модальное окно обычно отображается на панели задач. Если это нежелательно, для ShowInTaskbar необходимо установить значение false. Что я делаю обычно. Думаю, я спутал свои привычки с привычками WPF :) Я перепишу затронутые части своего ответа через мгновение ... - person ; 20.05.2017

Лучшее решение сделать ваше приложение одним экземпляром на отдельной машине - использовать Named Mutex.

Mutex

Вот отрывок из той же документации

Мьютексы бывают двух типов: локальные безымянные мьютексы и именованные системные мьютексы. Локальный мьютекс существует только в вашем процессе. Он может использоваться любым потоком в вашем процессе, который имеет ссылку на объект Mutex, представляющий мьютекс. Каждый безымянный объект Mutex представляет собой отдельный локальный мьютекс. Именованные системные мьютексы видны во всей операционной системе и могут использоваться для синхронизации действий процессов.

Вы можете создать объект Mutex, представляющий именованный системный мьютекс, с помощью конструктора, который принимает имя. Объект операционной системы может быть создан одновременно или существовать до создания объекта Mutex. Вы можете создать несколько объектов Mutex, которые представляют один и тот же именованный системный мьютекс, и вы можете использовать метод OpenExisting, чтобы открыть существующий именованный системный мьютекс.

И, в любом случае, вы разобрались со случаем, когда хотите запустить первый экземпляр.

person Gururaj    schedule 20.05.2017