Как я могу вывести мое приложение 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 с таймером, оно работает точно так, как ожидалось, поэтому я не уверен, почему он не работает в моем первоначальном случае.
Редактировать: Я делаю это в сочетании с глобальной горячей клавишей.
Хорошая мысль, но это единственное Окно в приложении.
Не могли бы вы дать немного больше кода контекста?





Хорошо, я понял, как обойтись. Я звоню с клавиатуры, которая используется для горячей клавиши. Вызов работает должным образом, если я помещаю его в 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 (как было предложено Мортеном) и другие предложения? Они кажутся менее хакерскими, чем этот признанный клудж.
Это было довольно давно, но да, в то время я пробовал это
Это не работает в моей Windows XP. Я рекомендую ответ @Matthew Xavier.
myWindow.Activate();
Пытается вывести окно на передний план и активирует его.
Это должно помочь, если я неправильно понял, и вы не хотите, чтобы поведение всегда было на вершине. В таком случае вам нужно:
myWindow.TopMost = true;
Я просто использовал myWindow.Show (), а иногда его не было наверху. Я сразу же позвонил в myWindow.Activate (), и это сработало.
Активация иногда не работает в Windows XP. Я рекомендую ответ @Matthew Xavier.
Немного странно, так как по умолчанию ShowActivated включено.
Первый ответ хороший, спасибо за это! Но вторая строка кода, использующая свойство Topmost, - плохая практика, поскольку она может скрывать другие всплывающие диалоговые окна и иметь неожиданное поведение.
Он не работает в Windows 7, если окно уже открыто, но ниже других окон
Не восстанавливает свернутые окна. Вам нужно будет сохранить последнее состояние окна и восстановить его или использовать хак Topmost.
На самом деле это можно сделать с помощью этого: if (myWindow.WindowState == WindowState.Minimized) myWindow.WindowState = WindowState.Normal; Как ни странно, он также сохранит все развернутые окна и не вернет их в нормальное состояние.
Я заставил это работать, вызвав его в событии Window Loaded. У меня не работало в конструкторе.
@MortenChristiansen В моем главном окне есть сетка данных, которая загружается из конструктора окна. Когда главное окно открывается из другого окна (которое обновляет данные), сетка данных обновляется обновленными данными. Ваше решение не обновило сетку данных обновленными данными. У меня сработало решение Этот от @Jader Dias. Однако ваше решение, вероятно, лучше подходит для некоторых других сценариев, таких как тот, который просил OP.
Если пользователь взаимодействует с другим приложением, возможно, не удастся вывести ваше на передний план. Как правило, процесс может ожидать установки окна переднего плана только в том случае, если этот процесс уже является процессом переднего плана. (Microsoft документирует ограничения в записи MSDN SetForegroundWindow ().) Это потому, что:
Хорошая точка зрения. Однако целью кода была связь с глобальной горячей клавишей, и другие приложения каким-то образом это делают.
Придется использовать PInvoke в C# для эмуляции того, что описано в этой статье, codeproject.com/Tips/76427/…
тогда почему всплывающие диалоговые окна ошибок смешивания выражений остаются видимыми, когда я иногда переключаюсь в визуальную студию? : - /
Саймон, я подозреваю, что всплывающие окна с ошибками, которые вы видите, являются "самыми верхними" окнами (дизайнерское решение, которое я не одобряю). Существует разница между окном переднего плана (которое принимает ввод пользователя) и «самым верхним» окном в Z-порядке. Любое окно может стать «самым верхним», что помещает его поверх всех окон, не являющихся самыми верхними, но не дает окну фокуса клавиатуры и т. д., Как это делает окно переднего плана.
Уловка не работает для нескольких специальных окон. В окнах Visual Studio и командной строки должно быть что-то, что предотвращает превращение другого окна в окно переднего плана.
Проблема может заключаться в том, что поток, вызывающий ваш код из ловушки, не был инициализирован средой выполнения, поэтому вызов методов среды выполнения не работает.
Возможно, вы могли бы попробовать выполнить 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#, вы должны заметить, что этот ответ почти бесполезен.
У меня была аналогичная проблема с приложением 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);
}
Я нашел решение, которое выводит окно наверх, но ведет себя как обычное окно:
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 за дополнительный комментарий о странном использовании TopMost!
Спасибо - исправление было коротким и приятным.
В моем случае было достаточно Window.Activate () и Window.Focus (). Настройка Window.TopMost не требуется.
Ваше добавление Window.Focus (); заставил меня понять, что мне это нужно в моем собственном коде! Спасибо!
Не используйте Window.Focus(). Это отвлечет внимание от того, что пользователь в данный момент вводит в текстовое поле, что безумно расстраивает конечных пользователей. Приведенный выше код отлично работает и без него.
Говоря о комментарии выше, у нас есть старая программа VB6, которая вызывает Window.Focus () при отображении предупреждения. Он выдает 5 предупреждений каждые 10 минут, и каждый раз он захватывает фокус, и пользователь теряет все, что набирал, и им приходится использовать мышь, чтобы вернуть курсор на место. Это сводит с ума сотни пользователей.
Самый верхний = истина; было то, что я искал. Спасибо
в моем случае window.Focus() полезен, потому что могут открываться другие окна в том же приложении, которые должны быть фоновыми окнами, и это используется только при запуске приложения. Для примера этого после ShowDialog() см. gist.github.com/ImaginaryDevelopment/…
Это умное решение, мне интересно, «исправила» ли Microsoft его позже, поскольку это нарушает их предполагаемую «защиту» вывода окон на передний план переключением атрибута «самый верхний».
Чтобы сделать это быстро скопируйте и вставьте один -
Используйте метод 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 это единственный ответ, который мне пригодился. У меня есть приложение с одним главным и несколькими плавающими подчиненными окнами. После активации любого из них все остальные окна также должны быть выведены на передний план. Но не активирован / получает фокус, как предлагают большинство ответов: это катастрофа, поскольку оно делает окно, которое в настоящее время щелкнуто, неактивным, поскольку внезапно другое окно получает фокус.
Есть ли причина не использовать process.MainWindowHandle?
В моем случае мне не нужно было главное окно, но я согласился, есть и другие способы получить hWnd. FWIW объект HwndSource работал хорошо.
Я знаю, что этот вопрос довольно старый, но я только что наткнулся на этот точный сценарий и хотел поделиться решением, которое я реализовал.
Как упоминалось в комментариях на этой странице, некоторые из предложенных решений не работают в 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)
На самом деле, это работает, только если я сделаю это: App.mainWindow.Show (); SystemWindows.GlobalActivate (App.mainwindow); // Когда я удаляю первый .show (), он не выводится на передний план
+1 для SetWindowPos (), я искал способ вывести только мое окно на передний план, не прерывая работу других приложений и не крадя фокус. this.Activate () крадет фокус.
Это помогло мне, и в моем случае вся суть заключалась в том, чтобы украсть фокус, как это происходило, когда пользователь взаимодействовал с определенным элементом. так что спасибо большое, это, похоже, работает последовательно! просто вызов this.Activate() срабатывает только несколько раз.
Что ж, раз это такая горячая тема ... вот что мне подходит. У меня были ошибки, если я этого не сделал, потому что 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 () не будет работать, если окно не активировано ();
У меня работает с экраном-заставкой, показываемым раньше. Спасибо.
Если вы пытаетесь скрыть окно, например, сворачиваете окно, я обнаружил, что с помощью
this.Hide();
скроет его правильно, тогда просто используя
this.Show();
затем снова отобразит окно как самый верхний элемент.
Я знаю, что это запоздалый ответ, может быть, полезно для исследователей
if (!WindowName.IsVisible)
{
WindowName.Show();
WindowName.Activate();
}
Любой ответ, в котором используется window.Focus(), неверен.
window.Focus() отвлечет внимание от всего, что пользователь набирает в данный момент. Это безумно расстраивает конечных пользователей, особенно если всплывающие окна появляются довольно часто.Любой ответ, в котором используется window.Activate(), неверен.
window.ShowActivated = false, неверен.
Visibility.Visible для скрытия / отображения окна, неверен.
window.Show() и window.Hide().По сути:
Этот код на 100% совместим с Citrix (на экране отсутствуют пустые области). Он протестирован как с обычным WPF, так и с DevExpress.
Этот ответ предназначен для любого варианта использования, когда нам нужно небольшое окно уведомления, которое всегда находится перед другими окнами (если пользователь выбирает это в настройках).
Если этот ответ кажется более сложным, чем другие, то это потому, что это надежный код корпоративного уровня. Некоторые другие ответы на этой странице просты, но на самом деле не работают.
Добавьте это присоединенное свойство к любому UserControl в окне. Прилагаемое свойство будет:
Loaded (иначе он не сможет найти в визуальном дереве родительское окно).В любой момент вы можете установить окно спереди или нет, перевернув значение присоединенного свойства.
<UserControl x:Class = "..."
...
attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
"{Binding EnsureWindowInForeground, Mode=OneWay}">
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 Это код корпоративного уровня. Я напечатал его по памяти, и именно этот метод используется в большой компании FTSE100. Реальная жизнь несколько менее чиста по сравнению с идеальными шаблонами дизайна, к которым мы все стремимся.
Мне не нравится тот факт, что мы сами сохраняем экземпляр окна в модели представления, поскольку Криптос упомянул, что это нарушает всю суть mvvm, может быть, это можно было бы сделать вместо этого в коде?
@ Игорь Месарош Согласен. Теперь, когда у меня больше опыта, если бы мне пришлось делать это снова, я бы добавил Behavior и управлял им с помощью Func<>, привязанного к ViewModel.
Эти коды будут работать нормально всегда.
Сначала установите активированный обработчик событий в 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
Привет Майк. Вы отвечаете на этот вопрос довольно поздно. Можете ли вы объяснить в своем ответе, почему этот подход отличается (и, возможно, лучше) от очень хороших ответов, которые уже были опубликованы на этот вопрос?
Только поздно, потому что мне просто нужно было это сделать, и я натолкнулся на это и хотел поделиться, как я решил проблему, и другие хотели это использовать.
Конечно, меня выбрали для просмотра вашего сообщения, и я хотел, чтобы вы знали. Всегда полезно дать новый ответ, если вы думаете, что это хороший вклад в развитие сообщества.
Этот вопрос был специально о WPF, но ваше решение предназначено для WinForms.
Вы убедились, что MainWindow - это именно то окно, которое вам нужно? Из MSDN: MainWindow автоматически устанавливается со ссылкой на первый объект Window, который будет создан в домене приложения.