2012-09-14 51 views
0

我正在使用Reactive UI爲Windows Phone 7.1開發我的第一個應用程序,而且我在使用ReactiveCollection類時遇到了困難。ReactiveCollection和無效的跨線程訪問

我的應用程序大致是關於訪問WP7 SQL CE引擎(LINQ to SQL)。我想使用ReactiveAsyncCommand在後臺執行數據操作。數據庫中的數據應該「自動地」出現在UI中,因此我決定使用ReactiveCollection作爲數據庫和UI之間的代理。

這裏是我的模型,所以你可以有一個更好的主意:

public class EncounteredModel 
{ 
    public ReactiveCollection<Fact> FactsCollection; 

    public ReactiveCollection<FactEntry> FactEntriesCollection; 

    private EncounteredModel() 
    { 
     using (EncounteredDataContext db = new EncounteredDataContext()) 
     { 
      FactsCollection = new ReactiveCollection<Fact>(from fact in db.Facts select fact); 
      FactEntriesCollection = new ReactiveCollection<FactEntry>(from factEntry in db.FactEntries select factEntry); 
     } 

     FactsCollection.ItemsAdded.Subscribe(fact => { using (var db = new EncounteredDataContext()) { db.Facts.InsertOnSubmit(fact); db.SubmitChanges(); } }); 
     FactsCollection.ItemsRemoved.Subscribe(fact => { using (var db = new EncounteredDataContext()) { db.Facts.DeleteOnSubmit(fact); db.SubmitChanges(); } }); 

     FactEntriesCollection.ItemsAdded.Subscribe(factEntry => { using (var db = new EncounteredDataContext()) { db.FactEntries.InsertOnSubmit(factEntry); db.SubmitChanges(); } }); 
     FactEntriesCollection.ItemsRemoved.Subscribe(factEntry => { using (var db = new EncounteredDataContext()) { db.FactEntries.DeleteOnSubmit(factEntry); db.SubmitChanges(); } }); 
    } 

    private static EncounteredModel instance; 

    public static EncounteredModel Instance 
    { 
     get 
     { 
      if (instance == null) 
       instance = new EncounteredModel(); 
      return instance; 
     } 
    } 

} 

在我的視圖模型我一直在使用2個不同的變種嘗試:

  1. 創建衍生反應的收集和綁定UI (使用ReactiveCollection.CreateDerivedCollection()方法,例如從EncounteredModel.FactsCollection派生而來,例如
  2. 使用ObservableAsPropertyHelper<IEnumerable<Fact>>,然後訂閱Model的ReactiveCollection Changed IObservable來填充OAPH。

不幸的是,兩種變體都會給我「無效的跨線程訪問」。堆棧跟蹤通常是這兩種方式的相同,這裏是一個變體1(縮短至顯著部分):

at MS.Internal.XcpImports.CheckThread() 
    at System.Windows.DependencyObject.GetValueInternal(DependencyProperty dp) 
    at System.Windows.FrameworkElement.GetValueInternal(DependencyProperty dp) 
    at System.Windows.DependencyObject.GetValue(DependencyProperty dp) 
    at System.Windows.Controls.ItemsControl.get_ItemsHost() 
    at System.Windows.Controls.ItemsControl.OnItemsChangedHandler(Object sender, ItemsChangedEventArgs args) 
    at System.Windows.Controls.ItemContainerGenerator.OnItemAdded(Object item, Int32 index, Boolean suppressEvent) 
    at System.Windows.Controls.ItemContainerGenerator.System.Windows.Controls.ICollectionChangedListener.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) 
    at System.Windows.Controls.WeakCollectionChangedListener.SourceCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e) 
    at System.Windows.Controls.ItemCollection.NotifyCollectionChanged(NotifyCollectionChangedEventArgs e) 

當我改變ReactiveCommand(不是異步之一),一切都很好。任何想法如何克服這一點?非常感謝提前。

回答

0

ReactiveCollection不會將所有內容都代理到UI線程,如果您從工作線程向其中添加項目,您將在該線程上發出UI併發出崩潰信號。

然而,一兩件事,ReactiveAsyncCommand爲你所做的就是給你回結果後面的UI線程上,這樣你就可以做這樣的事情:

var cmd = new ReactiveAsyncCommand(); 
cmd.RegisterAsyncFunc(() => getAllTheItems()) 
    .Subscribe(theItems => theItems.ForEach(item => collection.Add(item))); 

Subscribe保證是在UI線程上(如果不是,這是一個bug)

+0

嗨,感謝您的回答,它的工作原理(修改了一下我的需求,但我從你那裏得到了這個想法)。但是還有一個小問題:OAPH的故事是一樣的嗎?我的意思是,它是不是也將所有代碼都委託給UI線程? – Haspemulator

+0

OAPH還保證它的事件將在UI線程上被觸發,是的 –

相關問題