为什么这一页上的一些答案是错误的!
Any answer that uses window.Focus() is wrong.
Why? If a notification message pops up, window.Focus() will grab the focus away from whatever the user is typing at the time. This is insanely frustrating for end users, especially if the popups occur quite frequently.
Any answer that uses window.Activate() is wrong.
Why? It will make any parent windows visible as well.
Any answer that omits window.ShowActivated = false is wrong.
Why? It will grab the focus away from another window when the message pops up which is very annoying!
Any answer that does not use Visibility.Visible to hide/show the window is wrong.
Why? If we are using Citrix, if the window is not collapsed when it is closed, it will leave a weird black rectangular hold on the screen. Thus, we cannot use window.Show() and window.Hide().
从本质上讲:
当窗口激活时,它不应该从其他窗口抢夺焦点;
该窗口在显示时不应激活其父窗口;
该窗口应与Citrix兼容。
MVVM答案
此代码与Citrix 100%兼容(屏幕上没有空白区域)。它在普通WPF和DevExpress上都进行了测试。
这个答案适用于任何用例,其中我们想要一个小的通知窗口,它总是在其他窗口的前面(如果用户在首选项中选择了这个)。
如果这个答案看起来比其他答案更复杂,那是因为它是健壮的企业级代码。本页上的其他一些答案很简单,但实际上并不管用。
XAML -附加属性
将此附加属性添加到窗口中的任何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中,如果窗口离开屏幕,如何将窗口移到屏幕上?