窗口最小化/最大化/关闭时,DispatcherTimer会暂停

4

我试图用一个简单的应用程序来解释我的问题:

我有一个只有一个TextBlock的MainWindow。该TextBlock的属性Text与我的CTimer类的属性Seconds绑定。在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
}

我的问题 - 当我按下三个窗口按钮(最小化/最大化/关闭)中的任何一个并按住不放时,DispatcherTimer 会暂停并保持暂停状态,直到我松开按住的按钮。

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

3个回答

5
只要按下这些按钮之一,UI线程就会被阻塞。因为它是一个DispatcherTimer,它属于窗口的Dispatcher并在同一线程中运行。因此,如果该线程被阻塞,DispatcherTimer将停止运行。
您可以使用System.Timers.Timer。只要按住三个窗口按钮之一,UI就不会更新,但计时器仍会继续运行。

3
这是一种设计。DispatcherTimer只有在WPF Dispatcher循环执行时才能触发其Tick事件。当您调整窗口大小等操作时,Windows会启动自己的模态调度程序循环,此时不会触发该事件。
没有计时器类可以保证在请求间隔内运行回调函数,包括异步计时器,在这方面做得更好,因为它们可以在线程池线程上触发回调函数,所以不受UI线程中正在进行的任何事情的影响。但这也无法解决您的问题,您仍然需要使用dispatcher在UI线程上调用UIElement更新。
所以基本的错误在于您依赖于DispatcherTimer来计时。它不是为此而生的。Environment.TickCount和DateTime.UtcNow用于计时。只使用DispatcherTimer更新显示的值,从这些属性中计算实际值即可。

谢谢您的回答,也帮助了我,特别是让我意识到 DispatcherTimer 不适用于时间计数。 - flipis

1
原因很简单,因为在点击按钮时,你使用的是定时器正在运行的线程,而线程一次只能执行一件事。请查看MSDN上的DispatcherTimer Class页面获取更多信息。
从链接页面中获得:
DispatcherTimer 在每个 Dispatcher 循环的顶部进行重新评估。 不能保证计时器恰好在时间间隔发生时执行,但是保证不会在时间间隔发生之前执行。这是因为 DispatcherTimer 操作与其他操作一样被放置于 Dispatcher 队列中。当 DispatcherTimer 操作执行取决于队列中的其他任务及其优先级。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接