【问题标题】:WPF Windows Not Responding After Windows Sleep/ResumeWindows 睡眠/恢复后 WPF Windows 无响应
【发布时间】:2021-12-08 11:09:48
【问题描述】:

我有一个使用 .NET 5 的相当简单的 C# WPF 应用程序。基本上它位于后台并为最终用户计时特定事件。这些事件是从外部生成的 xml 文件构建的。

该应用程序由 2 个窗口组成,一个隐藏的窗口负责执行所有操作。如果它检测到某个事件到期,它会引发一条 toast 消息,单击该消息会打开另一个窗口以向用户显示事件详细信息。一切正常并按预期运行,除非在 Windows 睡眠/暂停和恢复之后。我们显然不希望事件在睡眠/暂停时累加,因此我们关闭隐藏窗口并在恢复时再次打开它。那里没有问题,但是一旦系统恢复并引发事件,可见窗口将拒绝显示。如果在睡眠/挂起发生时可见窗口是打开的,那么在恢复时整个窗口被冻结并拒绝响应(关闭窗口的唯一方法是杀死应用程序并重新启动)

APP代码如下:-

public static Forms.NotifyIcon notifyIcon;
public static MainWindow mw;
public static ConfigWindow cw;

protected override void OnStartup(StartupEventArgs e)
        {
            base.OnStartup(e);
            
            SystemEvents.PowerModeChanged += new PowerModeChangedEventHandler(SystemEvents_PowerModeChanged);
            // Listen to notification activation
            ToastNotificationManagerCompat.OnActivated += toastArgs =>
            {
                // Obtain the arguments from the notification
                ToastArguments args = ToastArguments.Parse(toastArgs.Argument);

                // Obtain any user input (text boxes, menu selections) from the notification
                ValueSet userInput = toastArgs.UserInput;

                // Need to dispatch to UI thread if performing UI operations
                    Application.Current.Dispatcher.Invoke(delegate
                    {
                        ToastControl.HandleToast(args);
                    });
            };

            ConfNotifyIcon();
            OpenApp();
        }

        private void ConfNotifyIcon()
        {
            notifyIcon = new Forms.NotifyIcon();
            notifyIcon.Icon = new System.Drawing.Icon("Images/Wellformation.ico");
            notifyIcon.DoubleClick += OnClick;
            notifyIcon.ContextMenuStrip = new Forms.ContextMenuStrip();
            notifyIcon.ContextMenuStrip.Items.Add("Open", System.Drawing.Image.FromFile("Images/Wellformation.ico"), OnClick);
            notifyIcon.ContextMenuStrip.Items.Add("Close", System.Drawing.Image.FromFile("Images/Wellformation.ico"), OnClose);
            notifyIcon.ContextMenuStrip.Items.Add(new Forms.ToolStripSeparator());
            notifyIcon.ContextMenuStrip.Items.Add("Exit", System.Drawing.Image.FromFile("Images/Wellformation.ico"), OnExit);
        }

        private void SystemEvents_PowerModeChanged(object sender, PowerModeChangedEventArgs e)
        {
            switch (e.Mode)
            {
                case PowerModes.Suspend:
                    this.Dispatcher.BeginInvoke((Action)(() =>
                    {
                        PrepareLock();
                    }), null);
                    break;
                case PowerModes.Resume:
                    this.Dispatcher.BeginInvoke((Action)(() =>
                    {
                        PrepareAwake();
                    }), null);
                    break;
                default:
                    break;
            }
        }

        private void PrepareAwake()
        {
            OpenApp();
            ConfNotifyIcon();
            notifyIcon.Visible = true;
        }

        private void PrepareLock()
        {
            notifyIcon.Dispose();
            cw.Close();
        }

        private void OnExit(object sender, EventArgs e)
        {
            Application.Current.Shutdown();
        }

        private void OnClose(object sender, EventArgs e)
        {
            mw.Close();
        }

        private void OnClick(object sender, EventArgs e)
        {
            OpenMain();
        }

        private void OpenMain()
        {
            mw = new();
            mw.Show();
            mw.Activate();
        }

public static void OpenApp()
        {
            cw = new ConfigWindow();
        }

隐藏的Window XAML如下:-

<Window x:Class="WellformationDesktopApplication.ConfigWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WellformationDesktopApplication"
        mc:Ignorable="d"
        Title="ConfigWindow" Height="1" Width="1" Visibility="Hidden" WindowState="Minimized">
    <Grid>
        
    </Grid>
</Window>

代码如下:-

Timer at = new();

        public ConfigWindow()
        {
            BuildConfig();
            InitializeComponent();
        }

        public void refreshconfig()
        {
            myObjects.Clear();
            myObjects = NudgeManager.GetNudges();
            NudgeHandler(myObjects);
        }

        public void BuildConfig()
        {
            myObjects.Clear();
            myObjects = GetEvents(); // pulls a list of event names with intervals from the config file
            EventHandler(myObjects); //Goes through the list of events and figures out when the next event is due based upon the interval in the configuration
            ActionTimer();
        }

        
        private void ActionTimer()
        {
            at.Interval = 60000;
            at.Elapsed += ChecktActions;
            at.AutoReset = true;
            at.Enabled = true;
        }

        private void ChecktActions(object sender, ElapsedEventArgs e)
        {
            //Go through the trigger times for all events and see if those time have passed, if they have raise a toast showing the event name.
            //If an event is raised reset the trigger time for the event based upon the interval and reset that time.
            
            }

可见窗口XAML如下:-

<Window x:Class="WellformationDesktopApplication.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WellformationDesktopApplication"
        mc:Ignorable="d"
        ResizeMode="NoResize"
        WindowStyle="None"
        Title="MainWindow" Height="500" Width="800" Background="{x:Null}" Foreground="{x:Null}" AllowsTransparency="True">

    <Grid x:Name="BG">
        <TextBlock x:Name="Display" HorizontalAlignment="Left" Margin="546,13,0,0" Text="Show event name and appropriate information about the event here..." VerticalAlignment="Top" FontSize="22"/>

    </Grid>
</Window>

代码如下:-

public MainWindow()
        {
            InitializeComponent();
            setstyles();
            this.MouseLeftButtonDown += delegate { DragMove(); };
        }

我们知道与 ConfigWindow 相关的一切工作正常,我们知道它在挂起时关闭,并在恢复时打开一个新的窗口,设置新的时间并且所有适当的警报都工作。

问题在于 MainWindow,因为在暂停和恢复之后,它根本无法交互。图标上的打开按钮什么也不做,如果打开的窗口完全冻结并且无法以任何方式进行交互,并且如果在窗口上单击 toast 则不会打开但其余的 toast 处理代码可以正常工作它。这发生在 Win8、Win10 和 Win11 上。

任何帮助,因为我完全不知道这是怎么发生的?

谢谢

【问题讨论】:

  • 在启动过程中,您首先调用ConfNotifyIcon(),然后调用OpenApp()。恢复后,您执行相反的操作。 ConfigWindow 中的任何内容是否依赖于该图标(是否希望首先创建它)?
  • 另外,从AutoReset 属性,我们可以推断您使用的是System.Timers.Timer 而不是WPF DispatcherTimer。这些计时器don't tick when the system is asleep,因此您似乎正在尝试围绕一个不存在的问题进行编程。
  • 还要注意Timer.SynchronizingObject Property 特别是"当SynchronizingObject 为null 时,处理Elapsed 事件的方法会在系统线程池中的一个线程上调用。" 我们看不到 ChecktActions 里面的内容,但如果你在这里操作 UI,这可能会有问题。
  • 回答之前的cmets。 ConfigWindow 和 NotifyIcon 之间没有链接。它们是没有代码连接的独立实体。暂停后重置计时器的原因是事件的计时基于机器的连续使用。完整的要求有点复杂,但最初的程序员这样做是有原因的。 ChecktActions 中唯一发生的事情是将 datetime now 与时间列表进行比较,如果事件的时间已经过去,则引发 Toast Notifications。没有进行任何 UI 操作。

标签: c# wpf windows


【解决方案1】:

经过大量工作并逐节浏览代码,将其注释掉,看看它是否有所作为,我发现了问题。

隐藏在隐藏窗口的代码深处(下一行调用了 4 次函数)我发现 EventHandler() 也为

SystemEvents.SessionSwitch += new SessionSwitchEventHandler(OnSessionSwitch);

所有相关函数都隐藏在一个单独的类中,该类不是从窗口本身直接引用的。

当此行被注释掉时,一切正常,在暂停/恢复窗口后将其放入隐藏窗口并附加到隐藏窗口,整个代码中不会发生 UI 更改(因此隐藏窗口继续完全正常工作)不与 UI 交互)。

通过将此代码提升到 APP 空间并在那里处理而不是在窗口中处理,问题就消失了(尽管已经发现了其他在 Windows 恢复时未处理的问题,我现在必须修复)。

所以答案是,对于任何类型的 SystemEvents 的 WPF 应用程序侦听器都需要位于 APP 代码空间中,而不是在窗口中。

【讨论】:

    猜你喜欢
    • 2021-11-27
    • 2011-05-18
    • 2020-09-02
    • 2023-04-04
    • 1970-01-01
    • 2011-11-22
    • 1970-01-01
    • 1970-01-01
    • 2016-07-31
    相关资源
    最近更新 更多