2011-07-07 105 views
1

我遇到了一個問題,即集合中的第一個項目正在響應更新,但沒有其他項目(滿分爲40)。我看了一遍網絡尋找答案,但不幸的是,在幾天之後,我仍然沒有得到任何幫助。螺紋應用程序問題

揭開序幕一個線程用於檢測循環調用代碼:

_detectionThread = new Thread(() => _x.StartDetection()); 
_detectionThread.Start(); 

Ive得到了我的助手類的一個下面的代碼簡單地投票和當檢測到的東西,通過事件的方式視圖模型被稱爲:

public event EventHandler SomethingIsDetected; 
private void OnSomethingDetected() 
     { 
      if (SomethingIsDetected!= null) 
      { 
       SomethingIsDetected(this, new EventArgs()); 
      } 
     } 

代碼檢測迴路:

var startCheckTime = DateTime.Now; 
      var nextCheck = startCheckTime.AddSeconds(PollingInterval.TotalSeconds); 

      while (_performDetection) 
      { 
       startCheckTime = DateTime.Now; 
       if (startCheckTime >= nextCheck) 
       { 
        nextCheck = startCheckTime.AddSeconds(PollingInterval.TotalSeconds); 

        { 
         var detectionTask = Task.Factory.StartNew(() => IsXConnected()); 
         IsXPresent = detectionTask.Result; 

         Thread.Sleep(TimeSpan.FromSeconds(1)); 

         if (IsXPresent) 
         { 
          Application.Current.Dispatcher.Invoke(new Action(OnSomethingDetected)); 
         } 
        } 
       } 
       Thread.Sleep(10); 
      } 

更新項目的代碼。視圖綁定到這裏的屬性(特別是CurrentItem)。項目是一個ObservableCollection

foreach (var item in Items) //loop through 40 items 
{ 
//do some operation then set the current item 
Application.Current.Dispatcher.Invoke(new Action(() => CurrentItem = item)); 
} 

雖然林步進通過(與調試器的幫助下)我注意到,該項目被udpated只是第一次。剩下的只是循環。我用一個DependencyProperty設置屬性CurrentItem。

我曾嘗試使用CheckAccess來使用Delegate和udpate屬性,並沒有幫助。

任何幫助,歡迎和感謝!

+2

1)何苦因爲您在下一行阻塞,所以創建一個調用IsXConnected的任務,直到操作完成。 2)什麼是IsXConnected在做什麼?既然這就是我在第一個結果後返回錯誤,這似乎很重要。3)我意識到foreach循環中有一些代碼設置CurrentItem = item,但是一開始它並沒有任何意義,因爲除非有阻塞調用,否則它會很快通過所有的Items和CurrentItem將最終成爲Items.Last,這將是UI將會看到的唯一的東西。 –

+0

感謝您的保羅,我得到了一個UI更新位的Debug.WriteLine,這表明只有第一個項目正在調用更新位。 (即使通過調用方法來處理點1,而沒有任務)。 – TheRenoRanger

+0

我相信從MainWindow.XAML.cs的構造函數執行線程是罪魁禍首。簽出[這](http://stackoverflow.com/questions/6639237/wpf-custom-control-dependencyproperty-issue)發佈更多信息。 – TheRenoRanger

回答

3

你的問題與多線程無關,它必須關閉如何在最後一段代碼中捕獲變量。你的lamba的所有共享相同的變量,即有一個item變量。由於您的lamda在循環結尾item後運行,將始終設置爲Items集合中的最後一個項目。 (雖然他們可能得到的任何項目上運行,這取決於具體什麼時候再運行)

編譯器將其轉換:

foreach (var item in Items) //loop through 40 items 
{ 
    //do some operation then set the current item 
    Application.Current.Dispatcher.Invoke(new Action(() => CurrentItem = item)); 
} 

的東西在道德上equivalend這樣:

class closuseCapture { 
    private ItemType itemCapture; 

    public void Loop() { 
     foreach (var item in Items) //loop through 40 items 
     { 
      itemCapture = item; 
      //do some operation then set the current item 
      Application.Current.Dispatcher.Invoke(new Action(ActionMethod)); 
     } 
    } 

    public void ActionMethod() { 
     CurrentItem = itemCapture; 
    } 

修復的方法是在循環中聲明一個變量,以便循環的每次交互都可以獲得它自己的項目副本:

foreach (var item in Items) //loop through 40 items 
{ 
    var localItem = item; 
    //do some operation then set the current item 
    Application.Current.Dispatcher.Invoke(new Action(() => CurrentItem = localItem)); 
}   

見任何或所有這些的更多信息或 「訪問修改關閉」 做一個谷歌搜索

http://devnet.jetbrains.net/thread/273042

Access to Modified Closure

Access to Modified Closure (2)

http://weblogs.asp.net/fbouma/archive/2009/06/25/linq-beware-of-the-access-to-modified-closure-demon.aspx

+0

感謝@ shf301。試圖宣佈一個局部變量,不幸的是,這也沒有任何幫助。我會看看我還能做些什麼...(另請閱讀你放置鏈接的東西)。乾杯。 – TheRenoRanger