4

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

我的 MainWindow 只有一个 TextBlock。此 TextBlock 的属性文本绑定到我的类 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 会暂停并保持暂停,直到我释放按下的按钮。

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

4

3 回答 3

5

只要您按下这些按钮之一,UI-Thread 就会被阻塞。因为它是一个DispatcherTimer,所以属于Window的Dispatcher,运行在同一个线程中。因此,如果此线程被阻塞,DispatcherTimer 将停止运行。

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

于 2013-09-11T12:04:23.417 回答
3

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

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

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

于 2013-09-11T12:09:55.553 回答
1

原因很简单,因为单击按钮时,您正在使用计时器正在运行的线程,并且该线程一次只能做一件事。请查看DispatcherTimer ClassMSDN 上的页面以获取更多信息。

从链接页面:

DispatcherTimer 在每个 Dispatcher 循环的顶部重新评估。

定时器不能保证在时间间隔发生时准确执行,但可以保证在时间间隔发生之前不会执行。这是因为 DispatcherTimer 操作像其他操作一样放置在 Dispatcher 队列中。DispatcherTimer 操作何时执行取决于队列中的其他作业及其优先级。

于 2013-09-11T12:03:36.670 回答