У меня есть приложение, которое имеет много модальных всплывающих окон. Некоторые из них являются пользовательскими окнами, отображаемыми с .ShowDialog()
, другие являются общими окнами сообщений с использованием стороннего инструмента (DXMessageBox.Show(...)
), а другие являются системными диалоговыми окнами, такими как OpenFileDialog
. Если пользователь оставляет приложение запущенным достаточно долго, ему следует установить тайм-аут и показать экран «Session Locked» и запретить пользователям видеть приложение или взаимодействовать с ним до тех пор, пока они не войдут в систему снова. Это проблематично из-за модальных диалогов.
Мое текущее решение - разместить экран Relogin в текущем модальном окне, если оно есть, и скрыть все остальные окна. Проблема в том, что если я установлю Visibility = Hidden
в любом окне, которое я вызвал с использованием .ShowDialog()
, оно будет рассматривать этот диалог как полученный результат и обрабатывать код, который обрабатывает результат диалога. Они также больше не являются модальными после повторного показа.
Итак, моя текущая попытка - попытаться скрыть окно, используя что-то отличное от Visibility, и предотвратить его активацию. Самое близкое, что я могу сделать, - это установить 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);
}