Fac*_*tic 210 .net c# wpf pinvoke winapi
如何将我的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);
Run Code Online (Sandbox Code Playgroud)
这些都没有Marshal.GetLastWin32Error()
成功(说这些操作成功完成,每个定义的P/Invoke属性都有SetLastError=true
).
如果我创建一个新的空白WPF应用程序,并SwitchToThisWindow
使用计时器调用,它完全按预期工作,所以我不知道为什么它不能在我的原始情况下工作.
编辑:我正在与全球热键一起做这个.
Mor*_*sen 301
myWindow.Activate();
Run Code Online (Sandbox Code Playgroud)
尝试将窗口置于前台并激活它.
这应该是诀窍,除非我误解了你想要永远在行为上.在这种情况下,你想要:
myWindow.TopMost = true;
Run Code Online (Sandbox Code Playgroud)
Jad*_*ias 159
我找到了一个将窗口置于顶部的解决方案,但它的行为与普通窗口相同:
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
Run Code Online (Sandbox Code Playgroud)
小智 32
如果您在第一次加载时需要窗口在前面,那么您应该使用以下内容:
private void Window_ContentRendered(object sender, EventArgs e)
{
this.Topmost = false;
}
private void Window_Initialized(object sender, EventArgs e)
{
this.Topmost = true;
}
Run Code Online (Sandbox Code Playgroud)
Her*_*ess 21
要使其快速复制粘贴 -
使用此类' 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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
HTH
Zod*_*man 18
我知道这个问题相当陈旧,但我刚刚遇到这个精确的场景,并希望分享我实施的解决方案.
正如本页评论中所提到的,所提出的一些解决方案不适用于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
/// <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
}
}
Run Code Online (Sandbox Code Playgroud)
我希望这段代码可以帮助遇到这个问题的其他人.
Mat*_*ier 13
如果用户正在与另一个应用程序进行交互,则可能无法将您的应用程序置于最前面.作为一般规则,如果该进程已经是前台进程,则进程只能设置前台窗口.(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();
}
Run Code Online (Sandbox Code Playgroud)
我知道这是迟到的答案,可能对研究人员有帮助
if (!WindowName.IsVisible)
{
WindowName.Show();
WindowName.Activate();
}
Run Code Online (Sandbox Code Playgroud)
任何使用的答案window.Focus()
都是错误的.
window.Focus()
则会将焦点从用户当时键入的内容中移开.这对最终用户来说是极其令人沮丧的,特别是如果弹出窗口经常发生的话.任何使用的答案window.Activate()
都是错误的.
window.ShowActivated = false
都是错误的.
Visibility.Visible
隐藏/显示窗口的答案都是错误的.
window.Show()
和window.Hide()
.实质上:
此代码与Citrix 100%兼容(屏幕没有空白区域).它使用普通WPF和DevExpress进行测试.
此答案适用于我们想要一个始终位于其他窗口前面的小通知窗口的任何用例(如果用户在首选项中选择此窗口).
如果这个答案看起来比其他答案更复杂,那是因为它是健壮的企业级代码.此页面上的其他一些答案很简单,但实际上并不起作用.
将此附加属性添加到UserControl
窗口中的任何属性.附属物业将:
Loaded
事件被触发(否则它无法查找可视树以查找父窗口).在任何时候,您都可以通过翻转附加属性的值将窗口设置在前面或不前面.
<UserControl x:Class="..."
...
attachedProperties:EnsureWindowInForeground.EnsureWindowInForeground=
"{Binding EnsureWindowInForeground, Mode=OneWay}">
Run Code Online (Sandbox Code Playgroud)
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".
}
}
}
Run Code Online (Sandbox Code Playgroud)
要使用它,您需要在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);
}
}
Run Code Online (Sandbox Code Playgroud)
有关如何确保通知窗口始终返回可见屏幕的提示,请参阅我的答案:在WPF中,如果窗口离开屏幕,如何将窗口移动到屏幕上?.
好吧,既然这是一个如此热门的话题……这对我有用。如果我不这样做,我会出错,因为如果您看不到窗口,Activate() 会出错。
Xml:
<Window ....
Topmost="True"
....
ContentRendered="mainWindow_ContentRendered"> .... </Window>
Run Code Online (Sandbox Code Playgroud)
代码隐藏:
private void mainWindow_ContentRendered(object sender, EventArgs e)
{
this.Topmost = false;
this.Activate();
_UsernameTextBox.Focus();
}
Run Code Online (Sandbox Code Playgroud)
这是我让窗口显示在顶部的唯一方法。然后激活它,这样您就可以在框中键入内容而无需使用鼠标设置焦点。control.Focus() 不会工作,除非窗口是 Active();
好吧,我想出了一个解决办法。我正在从用于实现热键的键盘挂钩进行调用。如果我将其放入后台工作人员并暂停,则该调用将按预期工作。这是一个拼凑,但我不知道为什么它最初不起作用。
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();
}
Run Code Online (Sandbox Code Playgroud)