2

私はここ数日 DispatcherTimer を見て過ごしましたが、まだいくつかのことに頭を悩ませることができません。ここまででわかるのは、

  1. ティック イベントが同時に 2 回発生することはありませんリンク
  2. ディスパッチャ タイマーがすべての作業を UI スレッドで自動的に実行するため、オブジェクトの所有者スレッドについて心配する必要はありません。
  3. ティックは基本的にキューから実行されるため、ティックのタイミングはあまり正確ではない場合があります

私がはっきりしていないのは、ティックイベントの間に実行される別のイベントがある場合に実行されるコードの順序です。ティックイベントが2つの機能を実行するDispatcherTimerを使用するテストWPFアプリケーションがあります。firstStep()そしてsecondStep()順番に。

firstStep()変数をnullsecondStep()設定し、null 以外の値に設定します。値を設定した後、secondStep() は、この変数へのアクセスを試みる Completed イベントを持つストーリーボードを開始します。

私の質問は、タイマーを実行し続けると、関数firstStep()と関数の間に Completed イベントが発生する可能性はありますか? secondStep()テスト アプリケーションを作成しましたが、そのように思われます。最終的に、Completed イベントが実行されると、変数が null の状態になります。しかし、それがどのように発生するのか理解できませんfirstStep().2secondStep()つの関数間でCompletedイベントを実行する方法はないはずです(またはここで間違っています)。UI スレッドは tick と Completed イベントを並行して実行しますか?

UI スレッドが例のストーリーボードの完了イベントやディスパッチャタイマーのティックなどのイベントを順番に実行する方法を詳しく説明してもらえますか? 読んでくれてありがとう、あなたのコメントはとても感謝しています。私はこれを回避するために一生懸命努力しています。以下は私が使用したテストコードです。しばらく実行すると、最終的にエラーがスローされます。

public partial class Window1 : Window
{
    public Window1()
    {
        InitializeComponent();

        storyBoardTest = new Storyboard();
        storyBoardTest.Completed += new EventHandler(storyBoardTest_Completed);
        DoubleAnimation animation = new DoubleAnimation(1, 0.9, new Duration(TimeSpan.FromSeconds(1)));
        Storyboard.SetTarget(animation, this);
        Storyboard.SetTargetProperty(animation, new PropertyPath(UIElement.OpacityProperty));
        storyBoardTest.Children.Add(animation);

        DispatcherTimer dt = new DispatcherTimer();
        dt.Interval = TimeSpan.FromMilliseconds(500);
        dt.Tick += new EventHandler(dt_Tick);
        dt.Start();

    }

    private Window windowTest = null;
    private Storyboard storyBoardTest = null;

    void dt_Tick(object sender, EventArgs e)
    {
        firstStep();
        secondStep();
    }

    private void firstStep()
    {
        windowTest = null;
    }

    private void secondStep()
    {
        windowTest = this;
        storyBoardTest.Stop();
        storyBoardTest.Begin(this);
    }

    void storyBoardTest_Completed(object sender, EventArgs e)
    {
        //Attempt to access object throws null error. Why?
        windowTest.Title = "test";
        windowTest = null;
    }
}

コールスタック:

WpfApplication1.exe!WpfApplication1.Window1.storyBoardTest_Completed(object sender = {System.Windows.Media.Animation.ClockGroup}, System.EventArgs e = null) 63 行目 C# PresentationCore.dll!System.Windows.Media.Animation.Clock.FireEvent (System.Windows.EventPrivateKey キー) + 0x5b バイト
PresentationCore.dll!System.Windows.Media.Animation.Clock.RaiseAccumulatedEvents() + 0x160 バイト
PresentationCore.dll!System.Windows.Media.Animation.TimeManager.RaiseEnqueuedEvents() + 0x60バイト
PresentationCore.dll!System.Windows.Media.Animation.TimeManager.Tick() + 0x28a バイト
PresentationCore.dll!System.Windows.Media.MediaContext.RenderMessageHandlerCore(object resizedCompositionTarget) + 0xbc バイト
PresentationCore.dll!System.Windows.Media.MediaContext.AnimatedRenderMessageHandler(オブジェクト resizedCompositionTarget) + 0x9d バイト

4

1 に答える 1

2

500 ミリ秒ごとに、1 秒間実行されるストーリーボードを開始しています。これにより、必然的Completedに、中間Tickイベントなしで 2 つの連続したイベントが発生します。

windowTestしたがって、すでにハンドラーにあるかどうかを確認する必要がnullあります。Completed

void storyBoardTest_Completed(object sender, EventArgs e)
{
    if (windowTest != null)
    {
        windowTest.Title = "test";
        windowTest = null;
    }
}

ストーリーボードの実行時間が 500 ミリ秒未満の場合でも、問題が発生します。イベントはイベントとStoryboard.Completed同じ方法で Dispatcher キューに追加され、DispatcherTimer.TickDispatcherTimer と Storyboard の両方のタイミングが正確ではないため、2 つのイベント ハンドラーの実行順序は信頼できません。したがってCompleted、中間Tickイベントなしで 2 つのイベントが発生する可能性があります。


トレース出力を追加して、両方のハンドラーが同じスレッドで実行されることを確認できます。

void dt_Tick(object sender, EventArgs e)
{
    Trace.TraceInformation("Tick: {0}", Thread.CurrentThread.ManagedThreadId);
    ...
}

void storyBoardTest_Completed(object sender, EventArgs e)
{
    Trace.TraceInformation("Completed: {0}", Thread.CurrentThread.ManagedThreadId);
    ...
} 
于 2013-02-16T12:49:59.607 に答える