2013-04-16 21 views
0

我有一個小程序,它是不低於運行,並更新視圖秒錶等等。在該視圖中,每8秒秒錶也會增加一個計數器。因此,在0,8,16,24秒等...計數器爲1,2,3,4等。更新相同的事件處理程序中的兩個視圖UI元素產生不穩定的結果

在XAML爲我的視圖我有幾個項,其中之一是將TextBlock拿着我的秒錶,另一個是另一個TextBlock,用於顯示「8秒過去」的次數。

<StackPanel Grid.Column="0" Orientation="Horizontal" HorizontalAlignment="Left" > 
    <Label Content="Run Time:" FontSize="16" FontWeight="Bold" Margin="10,0,0,0"/> 
    <TextBlock Name="ClockTextBlock" Text="00:00:00:00" FontSize="16" Foreground="Red" Margin="5" FontWeight="Bold"/> 
</StackPanel> 
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right"> 
    <Label Content="Sample Count:" FontSize="16" FontWeight="Bold" Margin="10,0,0,0"/> 
    <TextBlock Text="0" Name="SampleCountDigit" Foreground="Red" FontSize="16" FontWeight="Bold" Margin="5"/> 
</StackPanel> 

此xaml文件背後的代碼具有設置調度計時器的代碼,該調度計時器將創建我的秒錶。

public partial class StopWatchView: UserControl 
{ 
    private DispatcherTimer dt = new DispatcherTimer(); 
    private Stopwatch stopWatch = new Stopwatch(); 

    private string _currentTime = string.Empty; 
    private int _sampleCount = 0; 

    public StopWatchView() 
    { 
     InitializeComponent(); 

     dt.Tick += new EventHandler(dt_Tick); 
     dt.Interval = new TimeSpan(0, 0, 0, 0, 1); 
    } 

    private void dt_Tick(object sender, EventArgs e) 
    { 
     if (stopWatch.IsRunning) 
     { 
      TimeSpan ts = stopWatch.Elapsed; 

      _currentTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}", ts.Hours, ts.Minutes, ts.Seconds, 
             ts.Milliseconds/10); 

      ClockTextBlock.Text = _currentTime; 

      if (ts.Seconds%8 == 0) 
      { 
       _sampleCount++; 
       SampleCountDigit.Text = _sampleCount.ToString(); 
      } 
     } 
    } 

    private void StartButton_Click(object sender, RoutedEventArgs e) 
    { 
     ClockTextBlock.Foreground = Brushes.Green; 
     stopWatch.Start(); 
     dt.Start(); 
    } 

的問題

的代碼工作正常更新我的秒錶,使其外觀和行爲等應秒錶。每次調用dt_tick()並且if(stopWatch.IsRunning)的計算結果爲true時,視圖都會順利更新。當我遇到問題時,當if(ts.Seconds%8 == 0)爲真時_sampleCount增加。我不知道它的競爭條件(因爲我仍然在學習線程),但TextBox="SampleCountDigit"更新迅速和不正常8秒的間隔,因爲它應該。說實話,從我所知道的線程中,我不明白爲什麼會發生這種情況,或者爲什麼當dt_Tick()事件處理程序代碼中更新這兩個成員變量(_sampleCount和_currentTime)時,這將成爲競態條件。

爲什麼會變成這樣發生,我能做些什麼來更新我的SampleCountDigit(視圖),這樣每8秒,因爲它應該?應該在這個元素的更新周圍寫一個新的線程嗎?

編輯爲了提供更好的洞察問題的行爲,當我設置上SampleCountDigit.Text = _sampleCount.ToString();一個斷點的代碼完全停止在8,16,24秒,等等...和SampleDigitCounter我此後正確查看更新。因爲您所指定的計時器的時間間隔爲1毫秒

回答

2

的問題引起的。所以dt_tick()可能被調用到每秒1000次,在此期間值ts.Second不會改變。這會使_sampleCount每8秒增加1000。

在現實中,dt_tick將在由DispatcherTimer的能力和你的機器的速度決定的較低速率被調用。

您可能需要修改您的代碼是這樣的:

int _lastSeconds = -1; 

private void dt_Tick(object sender, EventArgs e) 
{ 
    if (stopWatch.IsRunning) 
    { 
     ... 

     if (ts.Seconds != _lastSeconds && ts.Seconds%8 == 0) 
     { 
      _lastSeconds = ts.Seconds; 
      _sampleCount++; 
      SampleCountDigit.Text = _sampleCount.ToString(); 
     } 
    } 
} 
+0

根據您對處理器速度的說法,將會更改間隔分辨率的幫助嗎?所以,而不是毫秒,我只需設置'dt.Interval =新TimeSpan(0,0,0,1)'? –

+1

我可能正在考慮具有> =〜50ms分辨率的Windows窗體計時器。 DispatcherTimer實際上可能會激發1000 /秒,我將不得不嘗試它。當然,如果dt_tick需要> 1ms運行,那麼這會限制你的速度。當然,將間隔設置爲1秒會更全面得多。 – Phil

1

你的直覺覺得這不是一個線程的問題是正確的,因爲你是在同一個方法修改這兩個變量,因此,在同一個線程。

你的問題實際上是相當直接的。我認爲你的dt_tick()方法每秒被調用一次以上。現在,如果你碰巧在同一秒內觸發了兩到三次,那麼「ts.Seconds」恰好是8的倍數,那麼你的計數器就會增加三次。

你這裏有另外一個輕微的問題是,你正在使用的不是「ts.TotalSeconds」「ts​​.Seconds」,我們將看到在下面的解決方案的影響。

解決這個問題的最好方法是使用ts.TotalSeconds來獲得自秒錶開始以來的絕對秒數,並在每次更新計數器時跟蹤該值。然後,您可以比較上次更新時間和現在,以查看是否已經過了8秒。重要的是使用ts.TotalSeconds而不是ts.Seconds,因爲ts.Seconds只是「秒針」,並且只能在0到59範圍內移動,所以你可以得到像時間倒退等奇怪的東西,如果你用它。

// Outside your dt_tick() 
double lastIncrementTime = 0.0d; 

// Inside your dt_tick(), just after ClockTextBlock.Text = _currentTime; 
if (ts.TotalSeconds - lastIncrementTime >= 8.0d) 
{ 
    // increment counter etc, then... 
    lastIncrementTime = ts.TotalSeconds; 
} 

這樣一來,無論你如何經常運行的代碼,你實際上是檢查是否8秒都因爲你遞增計數器最後一次通過,而不是檢查,看看是否對當前值秒手是8的倍數。

希望有幫助。

+0

+1用於解釋不使用TotalSeconds的警告。 –

相關問題