如何将我的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
使用计时器调用,它完全按预期工作,所以我不知道为什么它不能在我的原始情况下工作.
编辑:我正在与全球热键一起做这个.
myWindow.Activate();
尝试将窗口置于前台并激活它.
这应该是诀窍,除非我误解了你想要永远在行为上.在这种情况下,你想要:
myWindow.TopMost = true;
我找到了一个将窗口置于顶部的解决方案,但它的行为与普通窗口相同:
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
如果您在第一次加载时需要窗口在前面,那么您应该使用以下内容:
private void Window_ContentRendered(object sender, EventArgs e) { this.Topmost = false; } private void Window_Initialized(object sender, EventArgs e) { this.Topmost = true; }
要使其快速复制粘贴 -
使用此类' 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
我知道这个问题相当陈旧,但我刚刚遇到这个精确的场景,并希望分享我实施的解决方案.
正如本页评论中所提到的,所提出的一些解决方案不适用于XP,我需要在我的场景中支持.虽然我同意@Matthew Xavier的观点,即一般来说这是一个糟糕的用户体验,但有时候它完全是一个可信的用户体验.
将WPF窗口置于顶端的解决方案实际上是通过我用来提供全局热键的相同代码提供给我的.Joseph Cooney撰写的博客文章包含指向包含原始代码的代码示例的链接.
我已经清理并修改了一些代码,并将其作为System.Windows.Window的扩展方法实现.我已经在XP 32位和Win7 64位上进行了测试,两者都正常工作.
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 ////// Activate a window from anywhere by attaching to the foreground window /// 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 } }
我希望这段代码可以帮助遇到这个问题的其他人.
如果用户正在与另一个应用程序进行交互,则可能无法将您的应用程序置于最前面.作为一般规则,如果该进程已经是前台进程,则进程只能设置前台窗口.(Microsoft记录了SetForegroundWindow() MSDN条目中的限制.)这是因为:
用户"拥有"前景.例如,如果另一个程序在用户输入时偷走了前台,至少打断了她的工作流程,并且可能导致意外后果,因为她对一个应用程序的击键被犯罪者误解,直到她注意到更改,这将是非常烦人的.
想象一下,两个程序中的每一个都会检查它的窗口是否为前景,并尝试将其设置为前景(如果不是).一旦第二个程序运行,计算机就会变得无用,因为前台在每个任务切换时都会在两个程序之间反弹.
我遇到了类似的问题,WPF应用程序通过Shell对象从Access应用程序调用.
我的解决方案如下 - 适用于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(); }
我知道这是迟到的答案,可能对研究人员有帮助
if (!WindowName.IsVisible) { WindowName.Show(); WindowName.Activate(); }
任何使用的答案window.Focus()
都是错误的.
为什么?如果弹出通知消息,window.Focus()
则会将焦点从用户当时键入的内容中移开.这对最终用户来说是极其令人沮丧的,特别是如果弹出窗口经常发生的话.
任何使用的答案window.Activate()
都是错误的.
为什么?它还可以使任何父窗口可见.
任何省略的答案window.ShowActivated = false
都是错误的.
为什么?当消息弹出时,它将从另一个窗口抓住焦点,这非常烦人!
任何不用于Visibility.Visible
隐藏/显示窗口的答案都是错误的.
为什么?如果我们使用Citrix,如果窗口在关闭时没有折叠,它将在屏幕上留下一个奇怪的黑色矩形保持.因此,我们不能使用window.Show()
和window.Hide()
.
实质上:
当窗口激活时,窗口不应将焦点从任何其他窗口移开;
窗口显示时不应激活其父窗口;
该窗口应与Citrix兼容.
此代码与Citrix 100%兼容(屏幕没有空白区域).它使用普通WPF和DevExpress进行测试.
此答案适用于我们想要一个始终位于其他窗口前面的小通知窗口的任何用例(如果用户在首选项中选择此窗口).
如果这个答案看起来比其他答案更复杂,那是因为它是健壮的企业级代码.此页面上的其他一些答案很简单,但实际上并不起作用.
将此附加属性添加到UserControl
窗口中的任何属性.附属物业将:
等到Loaded
事件被触发(否则它无法查找可视树以查找父窗口).
添加一个事件处理程序,以确保窗口是否可见.
在任何时候,您都可以通过翻转附加属性的值将窗口设置在前面或不前面.
public static class HideAndShowWindowHelper { ////// Intent: Ensure that small notification window is on top of other windows. /// /// 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". } } ////// Intent: Ensure that small notification window can be hidden by other windows. /// /// 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(this, this, _toastViewWindow, true); } ShiftWindowOntoScreenHelper.ShiftWindowOntoScreen(_toastViewWindow); HideAndShowWindowHelper.ShiftWindowIntoForeground(_toastViewWindow); } private void HideWindow() { if (_toastViewWindow != null) { HideAndShowWindowHelper.ShiftWindowIntoBackground(_toastViewWindow); } }
有关如何确保通知窗口始终返回可见屏幕的提示,请参阅我的答案:在WPF中,如果窗口离开屏幕,如何将窗口移动到屏幕上?.