2

我是新來的異步編程和WP8,這是我的第一個應用程序,我有Dispatcher.BeginInvoke(..)的Windows Phone 8 Dispatcher.BeginInvoke不工作異步

中的一些問題的看法的背後我的代碼類,我試圖在第二個選項卡的數據透視scree異步加載數據。

這裏是我現在所擁有的:

public partial class ReminderPivot : PhoneApplicationPage 
    { 
     #region Reminder Members 
     private ReminderViewModel _model; 
     private IRepository _repository; 
     #endregion Reminder Members 

     #region Constructors 
     public ReminderPivot() 
     { 
      InitializeComponent(); 
      _model = new ReminderViewModel(); 
      _repository = new LocalStorageRepository(); 

      LoadData(); 
      LoadAsyncData(); 

      this.DataContext = _model; 

     } 
     #endregion Constructors 

     public void LoadData() 
     { 
      IEnumerable<Reminder> activeList = _repository.GetRemindersByStatusId(2); 
      if (activeList != null) 
      { 
       foreach (var reminder in activeList) 
       { 
        _model.ActiveReminders.Add(reminder); 
       } 
      } 
     } 
     public void LoadAsyncData() 
     {    
      Action action =() => 
      { 
       Thread.Sleep(5000); 

       IEnumerable<Reminder> inactiveList = _repository.GetRemindersByStatusId(3); 
       if (inactiveList != null) 
       { 
        _model.InctiveReminders = new System.Collections.ObjectModel.ObservableCollection<Reminder>(inactiveList); 
       } 
      }; 

      Dispatcher.BeginInvoke(action); 
     } 

的事情是,這仍然讓我的UI線程。我在這裏錯過了什麼?

編輯: 這個想法是加載數據異步到ViewModel ObservableCollection這是ModelBinded在XAML。

,如果我嘗試撥打電話異步另一個線程與Task.Factory(...)等讓說,這個崩潰,因爲我改變從另一個線程沒有UI線程的結合。

+0

我沒有看到你的代碼,表明異步使用...'Dispatcher.BeginInvoke'將在UI線程上執行代碼的任何東西,它纔剛剛派往是稍後執行! – 2013-03-01 19:23:07

+0

Hi @PedroLamas。那麼問題是,我如何加載是異步?如果我Task.Factory(..),並嘗試在一個單獨的線程創建它,那麼它將會崩潰,因爲我的列表我更新被綁定到ListBox .. – 2013-03-01 19:27:47

+1

在我看來,使用'Task.Factory'是絕對是最好的可能性在這裏... – 2013-03-01 19:34:36

回答

2

@PedroLamas我做到了工作,不知道這是最好的方式還是最優雅,但它能夠完成任務的建議後。

林做是需要時間來完成與Task.Factory另一個線程,使之awaitable,並在年底剛剛更新與調度程序的UI呼叫。

public async void LoadAsyncDataWithTask() 
     { 
      IEnumerable<Reminder> inactiveList = null; 
      Action action =() => 
      { 
       Thread.Sleep(2000); 
       inactiveList = _repository.GetRemindersByStatusId(2); 
      }; 

      await Task.Factory.StartNew(action); 

      Action action2 =() => 
      { 
       if (inactiveList != null) 
       { 
        foreach(var item in inactiveList) 
        { 
         _model.InctiveReminders.Add(item); 
        } 
       } 
      }; 

      Dispatcher.BeginInvoke(action2); 

     } 
+1

這將工作(+1)。你可能會做的做'GetRemindersByStatusId'異步讓事情在這個水平整潔的好一點:這取決於你的代碼的其餘部分。 – 2013-03-01 21:14:27

+1

隨着Windows Phone 8的我已經能夠做這樣的事情在一個lambda面前這個配售異步: Dispatcher.BeginInvoke(異步()=> { 等待 Task.Delay(125); TClock.RestTimerCanvas .Children.Clear(); }); – Stonetip 2013-05-31 14:31:29

1

雖然你已經找到了工作,並使用Task是非常先進的日期,使用Thread.Sleep你仍然阻斷線程池線程沒有很好的理由。

您可以通過使用一次性System.Threading.Timersee MSDN reference)來避免此問題,該問題將觸發其中一個(後臺)ThreadPool線程。然後在定時器回調結束時使用Dispatcher.BeginInvoke(...)來更新UI。

例如:

 var timer = new System.Threading.Timer(
      state => 
       { 
        // ... your code to run in background 

        // ... call BeginInvoke() when done 
        Dispatcher.BeginInvoke(() => MessageBox.Show("done")); 
       }, 
      null, 
      5000, 
      System.Threading.Timeout.Infinite); 
+0

嘿保羅,感謝您的信息,不知道+1。 Thread.Sleep只是爲了測試該方法正在工作(模擬更大的加載時間,更多的數據處理,努力工作等)。在生產代碼中這種東西不存在:-p。 – 2013-03-01 20:48:24