2016-11-14 85 views
1

所以我想將WPF的動態數據顯示合併到我的MVVM caliburn項目中(如果有人希望測試此動態數據顯示,我正在使用LineChart控件)錯誤)。有一個LineChart綁定到ObservableCollection。只有在具有LineChart的控件的代碼集合中進行收集時纔有效。如果嘗試綁定到集合ViewModel,則依賴項屬性會引發InvalidOperationException。這個問題怎麼解決?在MVVM中綁定WPF線程綁定訪問錯誤

我已經看到,當你改變屬性綁定到的集合並知道修復方法時,會發生這種情況,但絕不會在綁定的實際過程中發生。我已經嘗試在調度程序調用中創建集合(就像你要添加或刪除一樣),但它沒有幫助。

編輯:正如我在第二段中所述,異常不在更改集合。它是在約束點提出的。更重要的是,我試圖使用other question中的解決方案,但他們沒有幫助。

編輯#2:異常消息是「調用線程不能訪問此對象,因爲不同的線程擁有它」。人們總是告訴我解決方案的集合變化,但它甚至沒有得到改變。它在綁定階段失敗(ItemsSource =「{binding collection}」in xaml)。

編輯#3:我仔細檢查並注意到ViewModel是在UI線程中創建的,這隻會產生更多問題。

+0

可能的[ObservableCollection和線程]重複(http://stackoverflow.com/questions/2293246/observablecollection-and-threading) – dymanoid

+1

如果你可以發佈'StackTrace'或至少是'Message'你的'InvalidOperationException'。 – haindl

+0

@haindl我的不好,加了吧 –

回答

2

好吧,我花了很長時間才找到問題的根源。

與別人所懷疑的不同,這根本不是多線程問題。
相反,這是您正在使用的DynamicDataDisplay庫的問題。

有一個明確的理由,爲什麼你ListBox對象上的ItemsSource綁定工作,並且不會對Chart(的Microsoft.Research.DynamicDataDisplay.Markers2.LineChart型)工作:
Chart既不具有可視化,也不是一個邏輯父。

您可以檢查這個,如果你將以下代碼插入到Button_Click後他們設置一個斷點:

var visualParent = VisualTreeHelper.GetParent(Chart); 
var logicalParent1 = Chart.Parent; 
var logicalParent2 = LogicalTreeHelper.GetParent(Chart); 

你可以看到,他們都是null
因此,您在LineChart.ItemsSourceProperty上設置的BindingPath=ExampleCollection找不到任何源值,並且只將null分配給ItemsSource。這是因爲DataContext是從父級繼承的 - 但是當沒有父級時,則不會有任何DataContext繼承。
而且因爲Chart不是視覺或邏輯樹的一部分,所以沒有(容易)任何綁定到外部DataContext甚至可以工作。

要驗證DataContextnull剛加入這一行前面的代碼:

var dataContext = Chart.DataContext; 

現在有這三種可能的解決方案。
首先,您可以使用下面的代碼手動繼承WindowDataContext

private void Window_Loaded(object sender, RoutedEventArgs e) 
{ 
    // Just add the following line. 
    Chart.DataContext = DataContext; 

    Chart.StrokeThickness = 3; 
    Chart.SetBinding(LineChart.ItemsSourceProperty, new Binding("ExampleCollection")); 
    // ... 
} 

如果您只需添加這一條線,你會看到你的其他的多線程代碼工作得很好,圖表用某種正弦波模式更新。

,作爲另一種可能的解決方案,你可以諮詢爲DynamicDataDisplay庫中的文件和檢查正確的和預期的方式來分配ItemsSourceLineChart使用數據綁定。
我試圖自己搜索文檔,甚至在兩個小時左右的時間內從該庫中調試了大量代碼,但是文檔幾乎不存在,代碼太複雜,無法在幾個小時內完全理解。我嘗試使用幾種工具(Visual Studio Live Visual Tree,Snoop,...)來顯示ChartPlotter的可視化樹,但每次都得到StackOverflowException,所以本庫中的某些內容是有缺陷的。

,你可以使用一個Resource作爲一種代理對象的創建「結合橋樑」的MainWindowViewModel的同一個實例。
對於這個工作,你必須做這樣的事情在這裏建議:Data binding outside the visual tree. Data Context bridging

底線:所以,如果你只想把工作做好,我將設置DataContext代碼如上所示。 (特別是如果DataContext中的ViewModel的實例永遠不會改變。)
如果您想要使用純數據綁定,那麼我可能會使用「綁定橋」或搜索另一個支持此方案的圖表庫。

+0

非常感謝您提供的所有幫助和翔實的答案/評論! –

+0

@PaulVinogradov非常歡迎您!很高興我能幫助你! :-) – haindl

0

作爲THIS作爲THIS線程狀態您可以使用UI調度程序並調用UI線程上更改您的ObservableCollection的函數。 Application.Current.Dispatcher應該爲您提供UI調度程序。正如解決方案所示,它可以在ViewModel中正確使用。然而,一個更清潔和更通用的解決方案是對併發的仍然可觀察的集合,它仍然會存儲調度程序並在UI(或指定的)線程上運行更改。