2013-04-27 64 views
1

我對這個話題不是很有經驗,所以請原諒我,如果這不是很清楚。可移植類庫和ObservableCollection,更新UI線程

我創建了一個可移植類庫,它有一個ObservableCollection節,每個secion都有一個ObservableCollection的Items。

這兩個集合都綁定到單獨的Win8和WP8應用程序的UI。

我想弄清楚正確填充這些集合的正確方法,以便從PCL類更新UI。

如果這個類是在win8項目中的,我知道我可以做類似Dispatcher.BeginInvoke的事情,但是這不會轉化爲PCL,也不能在WP8項目中重用它。

在這個線程(Portable class library equivalent of Dispatcher.Invoke or Dispatcher.RunAsync)我發現了SynchroniationContext類。

我的主要應用程序的SynchroniationContext參考過去了,當我填充的部分我可以這樣做,因爲它是唯一被更新的一個對象:

if (SynchronizationContext.Current == _synchronizationContext) 
{ 
    // Execute the CollectionChanged event on the current thread 
    UpdateSections(sections); 
} 
else 
{ 
    // Post the CollectionChanged event on the creator thread 
    _synchronizationContext.Post(UpdateSections, sections); 
} 

然而,當我試圖做同樣的與文章的事情,我必須有一個參考部分和文章,但Post方法只允許我傳入一個單一的對象。

我試圖使用lambda表達式:

if (SynchronizationContext.Current == _synchronizationContext) 
    { 
// Execute the CollectionChanged event on the current thread 
    section.Items.Add(item); 
} 
else 
{ 
    // Post the CollectionChanged event on the creator thread 
    _synchronizationContext.Post((e) => 
    { 
     section.Items.Add(item); 
    }, null); 
} 

,但我猜這是不正確的,因爲我讓自己被「編組爲一個不同的線程」的錯誤。

那麼我在哪裏錯了?我如何從PCL正確更新這兩個集合,以便這兩個應用程序也可以更新他們的UI?

非常感謝!

回答

2

很難說沒有看到代碼的其餘部分,但我懷疑是與便攜式類庫有任何關係。很高興看到有關異常的細節(類型,消息和堆棧跟蹤)。

用多於參數調用Post()的方式看起來是正確的。如果您刪除if檢查並且總是經過SynchronizationContext.Post()會發生什麼情況?

順便說一句:我沒有明確通過SynchronizationContext。我假設ViewModel是在UI線程上創建的。這讓我捕捉到這樣的:

public class MyViewModel 
{ 
    private SynchronizationContext _context = SynchronizationContext.Current; 
} 
+0

當我這樣做時,上下文返回null。我不得不從應用程序中執行新的SynchronizationContext()以獲得傳入的值。奇怪的是,它不會馬上給我例外。它運行了幾次,然後在相同類型的數據上給我這個錯誤。但我最終放棄了將綁定從數據源直接轉移到viewmodel,我相信這是他們應該去哪裏 – SelAromDotNet 2013-04-28 19:52:22

1

我建議,至少在你的ViewModels,所有公開觀察到的狀態的變化(即屬性更改通知和修改ObservableCollections)發生在UI線程上。我建議在模型狀態更改時做同樣的事情,但讓他們在不同的線程上進行更改並將這些更改編組到ViewModel中的UI線程可能是有意義的。

要做到這一點,當然,您需要能夠切換到可移植代碼中的UI線程。如果SynchronizationContext不適合你,那麼只需爲調度器創建你自己的抽象(即IRunOnUIThread)。

0

您得到「編組在不同線程上」錯誤的原因是您沒有將項目作爲Post(action,state)方法上的「狀態」對象傳遞到列表中。

您的代碼應該是這樣的:

if (SynchronizationContext.Current == _synchronizationContext) 
    { 
// Execute the CollectionChanged event on the current thread 
    section.Items.Add(item); 
} 
else 
{ 
    // Post the CollectionChanged event on the creator thread 
    _synchronizationContext.Post((e) => 
    { 
     var item = (YourItemnType) e; 
     section.Items.Add(item); 
    }, item); 
} 

如果你做出的改變,你的代碼將正常工作從PCL。