代码之家  ›  专栏  ›  技术社区  ›  Sharun

WPF:在UI线程和后台线程之间传递对象

  •  2
  • Sharun  · 技术社区  · 17 年前

    在初始化组件后的窗口构造函数中,我需要创建一个对象并将其绑定到datagrid。由于创建对象花费的时间太长,窗口需要一段时间才能显示。因此,我决定将对象的创建转移到后台线程,并通过执行调度程序将其“委托回”到UI线程。调用以执行绑定。但这失败了。

    奇怪的是,如果我试图设置调度器中矩形的可见性。调用,但DataGrid不起作用。挫折不会!有什么想法吗?我在后台工作者和threadstart上也尝试过同样的方法,但我总是会遇到同样的错误。我无法访问DataGrid对象,即使它发生在dispatcher invoke委托中。我确信我在理解这个过程中遗漏了一些东西。如有任何建议,将不胜感激。谢谢

    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.
                              }            
    }
    

    使现代化 : 最后使用了一个调度程序 一旦 .将绑定代码放在它的标记中是有效的。但是我仍然很好奇为什么上面的代码没有。

    2 回复  |  直到 12 年前
        1
  •  0
  •   Akash Kava    17 年前

    我建议换一种方式。

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

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

    可以在XAML中定义CurrentModel与DataGrid或whichver控件的绑定。

    在你们这一方,代表调度员。调用只应设置CurrentModel,绑定将自动完成。

        2
  •  0
  •   Mathieu Garstecki    14 年前

    你打哪一个调度器 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线程的调度程序存储在一个字段中,但是使用控件的调度程序可以更好地显示代码的意图:“我想在这个控件所属的任何线程上调用它”。

    使现代化 :我刚刚意识到这是您控件的一个实例方法,所以您使用的dispatcher实例是正确的。这么晚才回答就到此为止。而且,你的代码对我来说很有用,用IEnumerable替换了你的模型。你的模特有什么特别的吗?