为什么这个页面上的一些答案是错误的!
基本上:
- 该窗口在激活时不应将焦点从任何其他窗口中抢走;
- 窗口在显示时不应激活其父窗口;
- 该窗口应与 Citrix 兼容。
MVVM 解决方案
此代码与 Citrix 100% 兼容(屏幕没有空白区域)。使用普通 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);
}
}
其他链接
有关如何确保通知窗口始终切换回可见屏幕的提示,请参阅我的回答:In WPF, how to shift a window onto the screen if it is off the screen?。