Вынести окно на передний план в WPF

Как я могу вывести мое приложение WPF на передний план рабочего стола? Пока я пробовал:

SwitchToThisWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle, true);

SetWindowPos(new WindowInteropHelper(Application.Current.MainWindow).Handle, IntPtr.Zero, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE);

SetForegroundWindow(new WindowInteropHelper(Application.Current.MainWindow).Handle);

Ни один из них не выполняет свою работу (Marshal.GetLastWin32Error() сообщает, что эти операции завершены успешно, а атрибуты P / Invoke для каждого определения действительно имеют SetLastError=true).

Если я создаю новое пустое приложение WPF и вызываю SwitchToThisWindow с таймером, оно работает точно так, как ожидалось, поэтому я не уверен, почему он не работает в моем первоначальном случае.

Редактировать: Я делаю это в сочетании с глобальной горячей клавишей.

Вы убедились, что MainWindow - это именно то окно, которое вам нужно? Из MSDN: MainWindow автоматически устанавливается со ссылкой на первый объект Window, который будет создан в домене приложения.

Todd White 03.11.2008 02:51

Хорошая мысль, но это единственное Окно в приложении.

Factor Mystic 03.11.2008 02:55

Не могли бы вы дать немного больше кода контекста?

Todd White 03.11.2008 04:02
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
223
3
186 071
18
Перейти к ответу Данный вопрос помечен как решенный

Ответы 18

Ответ принят как подходящий

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

void hotkey_execute()
{
    IntPtr handle = new WindowInteropHelper(Application.Current.MainWindow).Handle;
    BackgroundWorker bg = new BackgroundWorker();
    bg.DoWork += new DoWorkEventHandler(delegate
        {
            Thread.Sleep(10);
            SwitchToThisWindow(handle, true);
        });
    bg.RunWorkerAsync();
}

Просто интересно: вы пробовали Window.Activate (как было предложено Мортеном) и другие предложения? Они кажутся менее хакерскими, чем этот признанный клудж.

Simon D. 15.10.2009 00:10

Это было довольно давно, но да, в то время я пробовал это

Factor Mystic 15.10.2009 04:34

Это не работает в моей Windows XP. Я рекомендую ответ @Matthew Xavier.

Lex Li 18.09.2010 09:49
myWindow.Activate();

Пытается вывести окно на передний план и активирует его.

Это должно помочь, если я неправильно понял, и вы не хотите, чтобы поведение всегда было на вершине. В таком случае вам нужно:

myWindow.TopMost = true;

Я просто использовал myWindow.Show (), а иногда его не было наверху. Я сразу же позвонил в myWindow.Activate (), и это сработало.

Bermo 26.08.2009 08:54

Активация иногда не работает в Windows XP. Я рекомендую ответ @Matthew Xavier.

Lex Li 18.09.2010 09:47

Немного странно, так как по умолчанию ShowActivated включено.

greenoldman 26.05.2011 23:30

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

Jonathan Perry 22.07.2014 17:51

Он не работает в Windows 7, если окно уже открыто, но ниже других окон

Oleg Ignatov 06.08.2014 17:07

Не восстанавливает свернутые окна. Вам нужно будет сохранить последнее состояние окна и восстановить его или использовать хак Topmost.

r41n 21.02.2017 11:24

На самом деле это можно сделать с помощью этого: if (myWindow.WindowState == WindowState.Minimized) myWindow.WindowState = WindowState.Normal; Как ни странно, он также сохранит все развернутые окна и не вернет их в нормальное состояние.

r41n 21.02.2017 11:35

Я заставил это работать, вызвав его в событии Window Loaded. У меня не работало в конструкторе.

dev1998 03.05.2017 23:35

@MortenChristiansen В моем главном окне есть сетка данных, которая загружается из конструктора окна. Когда главное окно открывается из другого окна (которое обновляет данные), сетка данных обновляется обновленными данными. Ваше решение не обновило сетку данных обновленными данными. У меня сработало решение Этот от @Jader Dias. Однако ваше решение, вероятно, лучше подходит для некоторых других сценариев, таких как тот, который просил OP.

nam 05.06.2020 02:11

Если пользователь взаимодействует с другим приложением, возможно, не удастся вывести ваше на передний план. Как правило, процесс может ожидать установки окна переднего плана только в том случае, если этот процесс уже является процессом переднего плана. (Microsoft документирует ограничения в записи MSDN SetForegroundWindow ().) Это потому, что:

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

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

Factor Mystic 13.01.2009 01:52

Придется использовать PInvoke в C# для эмуляции того, что описано в этой статье, codeproject.com/Tips/76427/…

Lex Li 18.09.2010 09:45

тогда почему всплывающие диалоговые окна ошибок смешивания выражений остаются видимыми, когда я иногда переключаюсь в визуальную студию? : - /

Simon_Weaver 30.09.2010 09:37

Саймон, я подозреваю, что всплывающие окна с ошибками, которые вы видите, являются "самыми верхними" окнами (дизайнерское решение, которое я не одобряю). Существует разница между окном переднего плана (которое принимает ввод пользователя) и «самым верхним» окном в Z-порядке. Любое окно может стать «самым верхним», что помещает его поверх всех окон, не являющихся самыми верхними, но не дает окну фокуса клавиатуры и т. д., Как это делает окно переднего плана.

Matthew Xavier 06.10.2010 18:22

Уловка не работает для нескольких специальных окон. В окнах Visual Studio и командной строки должно быть что-то, что предотвращает превращение другого окна в окно переднего плана.

Lex Li 27.11.2010 16:28

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

Возможно, вы могли бы попробовать выполнить Invoke для маршалинга вашего кода в поток пользовательского интерфейса, чтобы вызвать ваш код, который выводит окно на передний план.

Если вам нужно, чтобы окно было впереди при первой загрузке, вы должны использовать следующее:

private void Window_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
}

private void Window_Initialized(object sender, EventArgs e)
{
    this.Topmost = true;
}

Если вы разрабатываете что-то похожее на Launchy (launchy.net) на C#, вы должны заметить, что этот ответ почти бесполезен.

Lex Li 18.09.2010 09:48

У меня была аналогичная проблема с приложением WPF, которое вызывается из приложения Access через объект Shell.

Мое решение ниже - работает в XP и Win7 x64 с приложением, скомпилированным для цели x86.

Я бы лучше сделал это, чем имитировал бы alt-tab.

void Window_Loaded(object sender, RoutedEventArgs e)
{
    // make sure the window is normal or maximised
    // this was the core of the problem for me;
    // even though the default was "Normal", starting it via shell minimised it
    this.WindowState = WindowState.Normal;

    // only required for some scenarios
    this.Activate();
}

Чтобы показать ЛЮБОЕ открытое в данный момент окно, импортируйте эту DLL:

public partial class Form1 : Form
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);
    [DllImportAttribute("User32.dll")]
    private static extern int SetForegroundWindow(int hWnd);

и в программе ищем приложение с указанным заголовком (пишем заголовок без первой буквы (индекс> 0))

  foreach (Process proc in Process.GetProcesses())
                {
                    tx = proc.MainWindowTitle.ToString();
                    if (tx.IndexOf("Title of Your app WITHOUT FIRST LETTER") > 0)
                    {
                        tx = proc.MainWindowTitle;
                        hWnd = proc.Handle.ToInt32(); break;
                    }
                }
                hWnd = FindWindow(null, tx);
                if (hWnd > 0)
                {
                    SetForegroundWindow(hWnd);
                }
"Название вашего приложения БЕЗ ПЕРВОЙ БУКВЫ" Уф, hacky hacky. Почему бы вместо этого не использовать IndexOf должным образом?
Lightness Races in Orbit 06.09.2019 15:28

Я нашел решение, которое выводит окно наверх, но ведет себя как обычное окно:

if (!Window.IsVisible)
{
    Window.Show();
}

if (Window.WindowState == WindowState.Minimized)
{
    Window.WindowState = WindowState.Normal;
}

Window.Activate();
Window.Topmost = true;  // important
Window.Topmost = false; // important
Window.Focus();         // important

Отличная подсказка! TopMost делает волшебство в Windows 7, если окно уже открыто, но ниже других окон.

gsb 29.09.2012 22:37

Это тоже помогло мне. Спасибо gsb за дополнительный комментарий о странном использовании TopMost!

Jen 15.07.2013 10:56

Спасибо - исправление было коротким и приятным.

code4life 07.05.2014 20:50

В моем случае было достаточно Window.Activate () и Window.Focus (). Настройка Window.TopMost не требуется.

virious 08.05.2014 18:08

Ваше добавление Window.Focus (); заставил меня понять, что мне это нужно в моем собственном коде! Спасибо!

jdnew18 11.11.2014 23:05

Не используйте Window.Focus(). Это отвлечет внимание от того, что пользователь в данный момент вводит в текстовое поле, что безумно расстраивает конечных пользователей. Приведенный выше код отлично работает и без него.

Contango 18.03.2016 15:45

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

Contango 18.03.2016 15:48

Самый верхний = истина; было то, что я искал. Спасибо

demo.b 09.04.2016 13:12

в моем случае window.Focus() полезен, потому что могут открываться другие окна в том же приложении, которые должны быть фоновыми окнами, и это используется только при запуске приложения. Для примера этого после ShowDialog() см. gist.github.com/ImaginaryDevelopment/…

Maslow 23.09.2016 16:12

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

dyasta 14.12.2016 16:00

Чтобы сделать это быстро скопируйте и вставьте один -
Используйте метод DoOnProcess этого класса, чтобы переместить главное окно процесса на передний план (но не для кражи фокуса из других окон)

public class MoveToForeground
{
    [DllImportAttribute("User32.dll")]
    private static extern int FindWindow(String ClassName, String WindowName);

    const int SWP_NOMOVE        = 0x0002;
    const int SWP_NOSIZE        = 0x0001;            
    const int SWP_SHOWWINDOW    = 0x0040;
    const int SWP_NOACTIVATE    = 0x0010;
    [DllImport("user32.dll", EntryPoint = "SetWindowPos")]
    public static extern IntPtr SetWindowPos(IntPtr hWnd, int hWndInsertAfter, int x, int Y, int cx, int cy, int wFlags);

    public static void DoOnProcess(string processName)
    {
        var allProcs = Process.GetProcessesByName(processName);
        if (allProcs.Length > 0)
        {
            Process proc = allProcs[0];
            int hWnd = FindWindow(null, proc.MainWindowTitle.ToString());
            // Change behavior by settings the wFlags params. See http://msdn.microsoft.com/en-us/library/ms633545(VS.85).aspx
            SetWindowPos(new IntPtr(hWnd), 0, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOACTIVATE);
        }
    }
}

HTH

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

stijn 23.12.2011 14:11

Есть ли причина не использовать process.MainWindowHandle?

Sriram Sakthivel 26.08.2014 10:06

В моем случае мне не нужно было главное окно, но я согласился, есть и другие способы получить hWnd. FWIW объект HwndSource работал хорошо.

tobriand 17.04.2015 19:32

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

Как упоминалось в комментариях на этой странице, некоторые из предложенных решений не работают в XP, что мне нужно поддерживать в моем сценарии. Хотя я согласен с мнением @Matthew Xavier, что в целом это плохая практика UX, бывают случаи, когда это вполне правдоподобный UX.

Решение для вывода окна WPF наверх было фактически предоставлено мне тем же кодом, который я использую для предоставления глобальной горячей клавиши. Статья в блоге Джозефа Куни содержит ссылка на его образцы кода, который содержит исходный код.

Я немного очистил и изменил код и реализовал его как метод расширения для System.Windows.Window. Я тестировал это на 32-разрядной версии XP и 64-разрядной версии Win7, оба из которых работают правильно.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Interop;
using System.Runtime.InteropServices;

namespace System.Windows
{
    public static class SystemWindows
    {
        #region Constants

        const UInt32 SWP_NOSIZE = 0x0001;
        const UInt32 SWP_NOMOVE = 0x0002;
        const UInt32 SWP_SHOWWINDOW = 0x0040;

        #endregion

        /// <summary>
        /// Activate a window from anywhere by attaching to the foreground window
        /// </summary>
        public static void GlobalActivate(this Window w)
        {
            //Get the process ID for this window's thread
            var interopHelper = new WindowInteropHelper(w);
            var thisWindowThreadId = GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);

            //Get the process ID for the foreground window's thread
            var currentForegroundWindow = GetForegroundWindow();
            var currentForegroundWindowThreadId = GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);

            //Attach this window's thread to the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);

            //Set the window position
            SetWindowPos(interopHelper.Handle, new IntPtr(0), 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW);

            //Detach this window's thread from the current window's thread
            AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);

            //Show and activate the window
            if (w.WindowState == WindowState.Minimized) w.WindowState = WindowState.Normal;
            w.Show();
            w.Activate();
        }

        #region Imports

        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

        [DllImport("user32.dll")]
        private static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId);

        [DllImport("user32.dll")]
        private static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach);

        [DllImport("user32.dll")]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        #endregion
    }
}

Надеюсь, этот код поможет другим, столкнувшимся с этой проблемой.

Эй, смотри! Я борюсь с этим месяцами! Это работает для обеих моих ситуаций. Потрясающий! (Windows 7 x64)

mdiehl13 10.07.2015 10:11

На самом деле, это работает, только если я сделаю это: App.mainWindow.Show (); SystemWindows.GlobalActivate (App.mainwindow); // Когда я удаляю первый .show (), он не выводится на передний план

mdiehl13 10.07.2015 10:25

+1 для SetWindowPos (), я искал способ вывести только мое окно на передний план, не прерывая работу других приложений и не крадя фокус. this.Activate () крадет фокус.

prettyvoid 21.08.2015 20:25

Это помогло мне, и в моем случае вся суть заключалась в том, чтобы украсть фокус, как это происходило, когда пользователь взаимодействовал с определенным элементом. так что спасибо большое, это, похоже, работает последовательно! просто вызов this.Activate() срабатывает только несколько раз.

Peter 18.07.2016 11:50

Что ж, раз это такая горячая тема ... вот что мне подходит. У меня были ошибки, если я этого не сделал, потому что Activate () выдаст ошибку, если вы не видите окно.

Xaml:

<Window .... 
        Topmost = "True" 
        .... 
        ContentRendered = "mainWindow_ContentRendered"> .... </Window>

Код позади:

private void mainWindow_ContentRendered(object sender, EventArgs e)
{
    this.Topmost = false;
    this.Activate();
    _UsernameTextBox.Focus();
}

Для меня это был единственный способ показать окно сверху. Затем активируйте его, чтобы вы могли вводить текст в поле, не устанавливая фокус с помощью мыши. control.Focus () не будет работать, если окно не активировано ();

У меня работает с экраном-заставкой, показываемым раньше. Спасибо.

SiL3NC3 09.07.2020 13:44

Если вы пытаетесь скрыть окно, например, сворачиваете окно, я обнаружил, что с помощью

    this.Hide();

скроет его правильно, тогда просто используя

    this.Show();

затем снова отобразит окно как самый верхний элемент.

Я знаю, что это запоздалый ответ, может быть, полезно для исследователей

 if (!WindowName.IsVisible)
 {
     WindowName.Show();
     WindowName.Activate();
 }

Почему некоторые ответы на этой странице неверны!

  • Любой ответ, в котором используется window.Focus(), неверен.

    • Почему? Если появится сообщение с уведомлением, window.Focus() отвлечет внимание от всего, что пользователь набирает в данный момент. Это безумно расстраивает конечных пользователей, особенно если всплывающие окна появляются довольно часто.
  • Любой ответ, в котором используется window.Activate(), неверен.

    • Почему? Он также сделает видимыми все родительские окна.
  • Любой ответ, в котором отсутствует window.ShowActivated = false, неверен.
    • Почему? Когда всплывает сообщение, он отвлекает внимание от другого окна, что очень раздражает!
  • Любой ответ, в котором не используется Visibility.Visible для скрытия / отображения окна, неверен.
    • Почему? Если мы используем Citrix, если окно не сворачивается при закрытии, на экране остается странный черный прямоугольник. Таким образом, мы не можем использовать window.Show() и window.Hide().

По сути:

  • Окно не должно отвлекать внимание от любого другого окна при его активации;
  • Окно не должно активировать своего родителя, когда оно отображается;
  • Окно должно быть совместимо с Citrix.

Решение MVVM

Этот код на 100% совместим с Citrix (на экране отсутствуют пустые области). Он протестирован как с обычным WPF, так и с DevExpress.

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

Если этот ответ кажется более сложным, чем другие, то это потому, что это надежный код корпоративного уровня. Некоторые другие ответы на этой странице просты, но на самом деле не работают.

XAML - прикрепленное свойство

Добавьте это присоединенное свойство к любому UserControl в окне. Прилагаемое свойство будет:

  • Подождите, пока не сработает событие Loaded (иначе он не сможет найти в визуальном дереве родительское окно).
  • Добавьте обработчик событий, который проверяет, будет ли окно видимым или нет.

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

<UserControl x:Class = "..."
         ...
         attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
             "{Binding EnsureWindowInForeground, Mode=OneWay}">

C# - вспомогательный метод

public static class HideAndShowWindowHelper
{
    /// <summary>
    ///     Intent: Ensure that small notification window is on top of other windows.
    /// </summary>
    /// <param name = "window"></param>
    public static void ShiftWindowIntoForeground(Window window)
    {
        try
        {
            // Prevent the window from grabbing focus away from other windows the first time is created.
            window.ShowActivated = false;

            // Do not use .Show() and .Hide() - not compatible with Citrix!
            if (window.Visibility != Visibility.Visible)
            {
                window.Visibility = Visibility.Visible;
            }

            // We can't allow the window to be maximized, as there is no de-maximize button!
            if (window.WindowState == WindowState.Maximized)
            {
                window.WindowState = WindowState.Normal;
            }

            window.Topmost = true;
        }
        catch (Exception)
        {
            // Gulp. Avoids "Cannot set visibility while window is closing".
        }
    }

    /// <summary>
    ///     Intent: Ensure that small notification window can be hidden by other windows.
    /// </summary>
    /// <param name = "window"></param>
    public static void ShiftWindowIntoBackground(Window window)
    {
        try
        {
            // Prevent the window from grabbing focus away from other windows the first time is created.
            window.ShowActivated = false;

            // Do not use .Show() and .Hide() - not compatible with Citrix!
            if (window.Visibility != Visibility.Collapsed)
            {
                window.Visibility = Visibility.Collapsed;
            }

            // We can't allow the window to be maximized, as there is no de-maximize button!
            if (window.WindowState == WindowState.Maximized)
            {
                window.WindowState = WindowState.Normal;
            }

            window.Topmost = false;
        }
        catch (Exception)
        {
            // Gulp. Avoids "Cannot set visibility while window is closing".
        }
    }
}

использование

Чтобы использовать это, вам нужно создать окно в вашей ViewModel:

private ToastView _toastViewWindow;
private void ShowWindow()
{
    if (_toastViewWindow == null)
    {
        _toastViewWindow = new ToastView();
        _dialogService.Show<ToastView>(this, this, _toastViewWindow, true);
    }
    ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(_toastViewWindow);
    HideAndShowWindowHelper.ShiftWindowIntoForeground(_toastViewWindow);
}

private void HideWindow()
{
    if (_toastViewWindow != null)
    {
        HideAndShowWindowHelper.ShiftWindowIntoBackground(_toastViewWindow);
    }
}

Дополнительные ссылки

Советы о том, как сделать так, чтобы окно уведомлений всегда возвращалось на видимый экран, см. В моем ответе: Как в WPF переместить окно на экран, если оно находится вне экрана?.

«Код корпоративного уровня» и несколькими строчками позже catch (Exception) { }. Да, верно ... И он использует код, который даже не показан в ответе, например _dialogService или ShiftWindowOntoScreenHelper. Плюс просьба создать окно на стороне viewmodel (что в основном нарушает весь шаблон MVVM) ...

Kryptos 31.08.2018 05:06

@Kryptos Это код корпоративного уровня. Я напечатал его по памяти, и именно этот метод используется в большой компании FTSE100. Реальная жизнь несколько менее чиста по сравнению с идеальными шаблонами дизайна, к которым мы все стремимся.

Contango 01.09.2018 11:06

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

Igor Meszaros 28.02.2019 16:46

@ Игорь Месарош Согласен. Теперь, когда у меня больше опыта, если бы мне пришлось делать это снова, я бы добавил Behavior и управлял им с помощью Func<>, привязанного к ViewModel.

Contango 05.03.2019 22:29

Эти коды будут работать нормально всегда.

Сначала установите активированный обработчик событий в XAML:

Activated = "Window_Activated"

Добавьте строку ниже в блок конструктора главного окна:

public MainWindow()
{
    InitializeComponent();
    this.LocationChanged += (sender, e) => this.Window_Activated(sender, e);
}

А внутри активированного обработчика событий скопируйте эти коды:

private void Window_Activated(object sender, EventArgs e)
{
    if (Application.Current.Windows.Count > 1)
    {
        foreach (Window win in Application.Current.Windows)
            try
            {
                if (!win.Equals(this))
                {
                    if (!win.IsVisible)
                    {
                        win.ShowDialog();
                    }

                    if (win.WindowState == WindowState.Minimized)
                    {
                        win.WindowState = WindowState.Normal;
                    }

                    win.Activate();
                    win.Topmost = true;
                    win.Topmost = false;
                    win.Focus();
                }
            }
            catch { }
    }
    else
        this.Focus();
}

Эти шаги будут работать нормально и выведут на передний план все остальные окна в окно своих родителей.

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

protected override void OnStartup(object sender, StartupEventArgs e)
{
    DisplayRootViewFor<IMainWindowViewModel>();

    Application.MainWindow.Topmost = true;
    Application.MainWindow.Activate();
    Application.MainWindow.Activated += OnMainWindowActivated;
}

private static void OnMainWindowActivated(object sender, EventArgs e)
{
    var window = sender as Window;
    if (window != null)
    {
        window.Activated -= OnMainWindowActivated;
        window.Topmost = false;
        window.Focus();
    }
}

Не забудьте не помещать код, который показывает это окно, в обработчик PreviewMouseDoubleClick, поскольку активное окно переключится обратно на окно, которое обработало событие. Просто поместите его в обработчик событий MouseDoubleClick или остановите всплытие, установив для e.Handled значение True.

В моем случае я обрабатывал PreviewMouseDoubleClick в Listview и не устанавливал e.Handled = true, тогда он поднял событие MouseDoubleClick, которое вернуло фокус обратно в исходное окно.

Я создал метод расширения, чтобы упростить его повторное использование.

using System.Windows.Forms;
    namespace YourNamespace{
        public static class WindowsFormExtensions {
            public static void PutOnTop(this Form form) {
                form.Show();
                form.Activate();
            }// END PutOnTop()       
        }// END class
    }// END namespace

Вызов конструктора форм

namespace YourNamespace{
       public partial class FormName : Form {
       public FormName(){
            this.PutOnTop();
            InitalizeComponents();
        }// END Constructor
    } // END Form            
}// END namespace

Привет Майк. Вы отвечаете на этот вопрос довольно поздно. Можете ли вы объяснить в своем ответе, почему этот подход отличается (и, возможно, лучше) от очень хороших ответов, которые уже были опубликованы на этот вопрос?

Noel Widmer 18.05.2017 21:24

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

Mike 19.05.2017 21:46

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

Noel Widmer 19.05.2017 22:20

Этот вопрос был специально о WPF, но ваше решение предназначено для WinForms.

Brian Reichle 20.05.2017 04:00

Другие вопросы по теме