我有一个具有很多模式弹出窗口的应用程序。一些是用.ShowDialog()
显示的自定义窗口,另一些是使用第三方工具(DXMessageBox.Show(...)
)的通用消息框,另一些是诸如OpenFileDialog
之类的系统对话框。如果用户让应用程序运行足够长的时间,它将超时并显示“会话锁定”屏幕,并阻止用户在再次登录之前看到或与应用程序交互。由于存在模式对话框,因此存在问题。
我当前的解决方案是在当前模态窗口(如果有的话)中托管“重新登录”屏幕,并隐藏所有其他窗口。问题是,如果我在使用Visibility = Hidden
调用的任何窗口上设置.ShowDialog()
,它将把该对话框视为已接收结果,并处理处理该对话框结果的代码。重新显示后,它们也不再是模态。
因此,我目前的尝试是尝试使用“可见性”以外的其他方式隐藏窗口,并防止其被激活。我最接近的是通过设置Minimized=true
和ShowInTaskbar=false
,但这会导致任务栏上方的标题栏最小化。
是否有防止这种情况发生的方法,或者有另一种隐藏窗口并防止其激活而不会导致.ShowDialog
返回的方法?
这里有一些代码可以重新创建示例应用程序进行测试。只需添加一个按钮即可启动ShowLock_Click
事件处理程序。
private readonly Dictionary<System.Windows.Window, WindowStyle> _hiddenWindows = new Dictionary<System.Windows.Window, WindowStyle>();
// Create a button to launch this for testing
private void ShowLock_Click(object sender, RoutedEventArgs e)
{
// Will show another window with .ShowDialog, then 2s timeout will trigger lock window
using (new System.Threading.Timer(OnLockTimerElapsed, null, 2000, System.Threading.Timeout.Infinite))
{
ShowTestDialog();
}
}
private void OnLockTimerElapsed(object state)
{
_hiddenWindows.Clear();
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() =>
{
var mainWindow = Application.Current.MainWindow;
Window host = null;
foreach (Window win in Application.Current.Windows)
{
if (IsModalDialog(win))
host = win;
_hiddenWindows.Add(win, win.WindowStyle);
// Been testing various ways to hide window without using Visibility
win.ShowInTaskbar = false;
win.WindowStyle = WindowStyle.None;
win.WindowState = WindowState.Minimized;
win.Opacity -= 1;
win.IsHitTestVisible = false;
}
ShowLockScreen(host);
}));
}
private void ShowLockScreen(Window owner = null)
{
var lockScreen = new Window
{
Title = "Relogin Window",
Content = "This is a test Relogin Window. Close Window via X to continue",
WindowStartupLocation = WindowStartupLocation.CenterScreen
};
if (owner != null)
lockScreen.Owner = owner;
lockScreen.ShowDialog();
// Once that window closes, restore other windows
RestoreSession();
}
private void RestoreSession()
{
Application.Current.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() =>
{
foreach (var win in _hiddenWindows.Keys)
{
win.ShowInTaskbar = true;
win.WindowStyle = _hiddenWindows[win];
win.WindowState = WindowState.Normal;
win.IsHitTestVisible = true;
win.Opacity += 1;
}
}));
}
private void ShowTestDialog()
{
var test = new Window
{
Title = "Test Modal Dialog",
Content = "This is a test Modal Dialog. Close window via X to continue.",
Height = 100,
Width = 350,
WindowStartupLocation = WindowStartupLocation.CenterOwner,
Owner = this
};
var result = test.ShowDialog();
// This code gets run if I set Visibility=Hidden. I do not want that.
MessageBox.Show($"Test Dialog result returned. Result : {result}. This should ONLY happen when you click X on the dialog window");
}
private static bool IsModalDialog(Window window)
{
return (bool)typeof(System.Windows.Window)
.GetField("_showingAsDialog", System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.NonPublic)
.GetValue(window);
}