Как я могу скрыть окно без свойства видимости? - PullRequest
1 голос
/ 21 июня 2019

У меня есть приложение, которое имеет много модальных всплывающих окон. Некоторые из них являются пользовательскими окнами, отображаемыми с .ShowDialog(), другие являются общими окнами сообщений с использованием стороннего инструмента (DXMessageBox.Show(...)), а другие являются системными диалоговыми окнами, такими как OpenFileDialog. Если пользователь оставляет приложение запущенным достаточно долго, ему следует установить тайм-аут и показать экран «Session Locked» и запретить пользователям видеть приложение или взаимодействовать с ним до тех пор, пока они не войдут в систему снова. Это проблематично из-за модальных диалогов.

Мое текущее решение - разместить экран Relogin в текущем модальном окне, если оно есть, и скрыть все остальные окна. Проблема в том, что если я установлю Visibility = Hidden в любом окне, которое я вызвал с использованием .ShowDialog(), оно будет рассматривать этот диалог как полученный результат и обрабатывать код, который обрабатывает результат диалога. Они также больше не являются модальными после повторного показа.

Итак, моя текущая попытка - попытаться скрыть окно, используя что-то отличное от Visibility, и предотвратить его активацию. Самое близкое, что я могу сделать, - это установить Minimized=true и ShowInTaskbar=false, но это приводит к нежелательному свёрнутому заголовку заголовка над моей панелью задач.

Screenshot

Есть ли способ предотвратить это или же есть другой способ скрыть окно и запретить его активацию, не вызывая .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);
}
...