4

シンプルなアプリで私の問題を説明しようとしています:

TextBlock が 1 つだけの MainWindow があります。この TextBlock のプロパティ テキストは、クラス CTimer のプロパティ Seconds にバインドされます。MainWindow には、1 秒ごとに 1 つの単純なことを行う 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
}

私の問題 - 3 つのウィンドウ ボタン (最小/最大/閉じる) のいずれかを押したままにすると、DispatcherTimer が一時停止し、押したボタンを離すまで一時停止したままになります。

誰かがこの動作の原因を知っていますか?

4

3 に答える 3

3

これは仕様によるものです。DispatcherTimer は、WPF ディスパッチャー ループの実行中にのみ Tick イベントを発生させることができます。ウィンドウのサイズを変更するときなどに使用される、Windows が独自のモーダル ディスパッチャー ループを開始するときはそうではありません。

要求された間隔で実行されることが保証されているコールバックを提供できる Timer クラスはありません。非同期タイマーを含めると、スレッドプール スレッドでコールバックを起動できるため、UI スレッドで何が起こっても影響を受けないため、より適切に機能します。しかし、それでも問題は解決しません。UI スレッドで UIElement の更新を呼び出すには、ディスパッチャが必要です。

したがって、基本的な間違いは、時間を維持するために DispatcherTimer に依存していることです。そのために作られているわけではありません。Environment.TickCount と DateTime.UtcNow は時間を保持します。DispatcherTimer のみを使用して表示された値を更新し、これらのプロパティのいずれかから実際の値を計算します。

于 2013-09-11T12:09:55.553 に答える
1

その理由は単純で、ボタンをクリックすると、タイマーが実行されているスレッドが使用され、スレッドは一度に 1 つのことしか実行できないためです。詳細DispatcherTimer Classについては、MSDN のページを参照してください。

リンクされたページから:

DispatcherTimer は、すべての Dispatcher ループの先頭で再評価されます。

タイマーは、時間間隔が発生したときに正確に実行されることは保証されていませんが、時間間隔が発生する前に実行されないことは保証されています。これは、DispatcherTimer 操作が他の操作と同様に Dispatcher キューに置かれるためです。DispatcherTimer 操作が実行されるタイミングは、キュー内の他のジョブとその優先度に依存します。

于 2013-09-11T12:03:36.670 に答える