调度程序计时器在最小化/最大化/关闭窗口时暂停

本文关键字:窗口 暂停 最大化 计时器 最小化 调度程序 | 更新日期: 2023-09-27 18:31:04

我尝试在简单的应用程序上解释我的问题:

我有一个只有一个文本块的主窗口。此文本块的属性文本绑定到我的类 CTimer 的属性秒。在 MainWindow 中,我还有一个 DispatcherTimer 每秒做一件简单的事情 - 递增对象的 Seconds 属性。

MainWindow.xaml:

<Window x:Class="Try.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
        <TextBlock Name="txtTime" Text="{Binding Seconds}" VerticalAlignment="Center" HorizontalAlignment="Center" FontSize="16" FontWeight="Bold"/>
    </Grid>
</Window>

MainWindow.xaml.cs:

public partial class MainWindow : Window
{
    private CTimer timer = new CTimer();
    private DispatcherTimer ticker = new DispatcherTimer();
    public MainWindow()
    {
        InitializeComponent();
        ticker.Tick += AddSeconds;
        ticker.Interval = TimeSpan.FromSeconds(1);
        txtTime.DataContext = timer;
        ticker.Start();
    }
    public void AddSeconds(object sender, EventArgs e) 
    {
        timer.Seconds++;
    }
}

CTimer.cs:

public class CTimer:INotifyPropertyChanged
{
    private int seconds = 0;
    public int Seconds
    {
        get { return seconds; }
        set 
        { 
            seconds = value;
            OnPropertyChanged("Seconds");
        }
    }
    #region INotifyPropertyChanged Members
    public event PropertyChangedEventHandler PropertyChanged;
    protected virtual void OnPropertyChanged(string propertyName)
    {
        if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }
    #endregion
}

我的问题 - 当我按下三个窗口按钮(最小/最大/关闭)中的任何一个并按住它时,调度程序计时器会暂停并保持暂停状态,直到我松开按下的按钮。

有人知道这种行为的原因吗?

调度程序计时器在最小化/最大化/关闭窗口时暂停

只要按下这些按钮之一,UI 线程就会被阻止。因为它是调度程序计时器,所以它属于窗口的调度程序并在同一线程中运行。因此,如果此线程被阻塞,调度程序计时器将停止运行。

您可以使用System.Timers.Timer.只要按住三个窗口按钮之一,UI 就不会更新,但计时器将继续运行。

这是设计使然。 DispatcherTimer 只能在 WPF 调度程序循环正在执行时触发其 Tick 事件。 当 Windows 启动自己的模式调度程序循环时,它不会,例如,当您调整窗口大小时使用。

没有 Timer 类能够为您提供保证以请求的间隔运行的回调。 包括异步计时器,它们在这方面做得更好,因为它们可以在线程池线程上触发回调,因此不受 UI 线程中发生的任何情况的影响。 但这也不能解决您的问题,您仍然需要调度程序在 UI 线程上调用 UIElement 更新。

所以基本的错误是你依靠调度程序计时器来保持时间。 它不是为此而生的。 Environment.TickCount 和 DateTime.UtcNow 保持时间。 仅使用调度程序计时器更新显示的值,从这些属性之一计算实际值。

原因很简单,因为当单击按钮时,您正在使用运行计时器的线程,并且线程一次只能做一件事。有关详细信息,请查看 MSDN 上的DispatcherTimer Class页。

从链接页面:

调度程序

计时器在每个调度程序循环的顶部重新计算。

计时器不保证在时间间隔发生时准确执行,但保证它们不会在时间间隔发生之前执行。这是因为调度程序计时器操作与其他操作一样放置在调度程序队列中。调度程序计时器操作的执行时间取决于队列中的其他作业及其优先级。