2009-07-25 257 views
2

在我的Window构造函数InitializeComponents后,我需要创建一个对象并将其绑定到一个数据网格。由于创建对象花费的时间太多,所以窗口需要一段时间才能显示出来。所以我决定将对象的创建移动到后台线程,并通过执行dispatcher.invoke来执行绑定,将其“委托回”到UI线程。但是这失败了。WPF:在UI线程和后台线程之间传递对象

奇怪的是,如果我尝试设置一个矩形的可见性,我有Dispatcher.invoke里面的工作,但DataGrid.setbinding没有!有任何想法吗?我已经尝试过与后台工作者和threadstart相同的事情,但我一直得到相同的错误。我无法访问DataGrid对象,即使它发生在调度程序内调用委托。我确定在理解其工作原理时错过了一些东西。任何建议将不胜感激。谢谢!

StartupDelegate s = new StartupDelegate(CreateModel); 
s.BeginInvoke(delegate(IAsyncResult aysncResult) { s.EndInvoke(aysncResult); }, null); 

internal CreateModel() 
{ 
    Model d = new Model(); 
    Dispatcher.Invoke(DispatcherPriority.Normal, 
         new Action<Model>(
          delegate(Model d1) 
          { 
           mModel = d1; // mModel is a property defined in Window 
           Binding b = new Binding(); 
           b.Source = mModel; 
           MainDataGrid.SetBinding(TreeView.ItemsSourceProperty, mainb); // << dies here with - The calling thread cannot access this object because a different thread owns it. 
          }    
} 

UPDATE: 结束了使用,将只运行一次一个 dispatchertimer。将绑定代码放在它的Tick委托中。但我仍然很好奇为什么上面的代码没有。

回答

0

我会建议另一种方法。

不应该从代码调用绑定,而应该在XAML中定义它。

您可以在窗口上添加一个类型为Model的DependencyProperty,并将其称为“CurrentModel”并将其初始值设置为NULL。看起来你已经有一个名为mModel的属性,那是DependencyProperty?

您可以定义CurrentModel的绑定到DataGrid或XAML中的哪个控件。

而在委托结束时,Dispatcher.Invoke应该只设置CurrentModel,绑定将自动完成。

+0

我曾尝试过这种不在xaml中,但只是设置绑定到属性,属性为null。所以代表只有一行mModel = d1。但没有发生。它不是一个依赖属性,而是一个实现notifypropertychanged的普通属性。 – Sharun 2009-07-25 13:06:47

0

调用哪个调度程序实例Invoke

我猜这是来自执行CreateModel的后台线程的调度程序,而不是来自UI线程的调度程序。

DataGrid是一个控件,所以从DispatcherObject派生。每个这样的对象通过它的Dispatcher属性公开其拥有者线程的调度器,这是你应该用来调用控件方法的那个。

更改呼叫调度员应该工作:

internal CreateModel() 
{ 
    Model d = new Model(); 

    // Invoke the action on the dispatcher of the DataGrid 
    MainDataGrid.Dispatcher.Invoke(DispatcherPriority.Normal, 
         new Action<Model>(
          delegate(Model d1) 
          { 
           mModel = d1; // mModel is a property defined in Window 
           Binding b = new Binding(); 
           b.Source = mModel; 
           MainDataGrid.SetBinding(TreeView.ItemsSourceProperty, mainb); 
          }    
} 

你也可以执行后台操作之前存储在一个领域UI线程的调度,但使用的控制更好的调度表明意图的代码:“我想调用此控件属于的任何线程”。

更新:我只是意识到这是您的控件的实例方法,因此您使用的调度程序实例是正确的。非常适合深夜回答。此外,您的代码适用于我,用IEnumerable替换您的模型。你的模型中有什么特别的东西?

相关问题