2016-11-14 68 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(或指定的)线程上运行更改。