简体   繁体   中英

WPF: Passing objects between UI Thread and Background thread

In my Window constructor after InitializeComponents, I need to create an object and bind it to a datagrid. Since the object creation is taking too much time, the windows takes a while to show up. So I decided to move the creation of the object to a background thread and "delegate back" to the UI thread by doing a dispatcher.invoke to perform the binding. But this fails.

The weird thing is if I try to set the visibility of a rectangle I have inside the Dispatcher.invoke, that works but the DataGrid.setbinding doesnt! Any ideas? I have tried the same thing with background worker, and threadstart, but I keep getting the same error. I am not able to access the DataGrid object even though its happening inside the dispatcher invoke delegate. Am sure am missing something in my understanding of how this works. Any suggestions would be greatly appreciated. Thanks!

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 : Ended up using a dispatchertimer that would run just once . Putting the binding code in its Tick delegate worked. But I am still curious why the above code doesnt.

I would suggest another way around.

Binding should not be called from code, instead you should define it in XAML.

You can add one more DependencyProperty of type Model on your window and call it "CurrentModel" and set its initial value to NULL. Looks like you already have a property called mModel, is that DependencyProperty?

You can define Binding of CurrentModel to DataGrid or whichver control in XAML.

And in your end of delegate, the Dispatcher.Invoke should only set CurrentModel, the binding will be done automatically.

On what dispatcher instance are you calling Invoke ?

I'm guessing it is the Dispatcher from the background thread that is executing CreateModel , not the one from the UI thread.

The DataGrid is a control, and so derives from DispatcherObject . Each such object exposes the dispatcher of its owner thread through its Dispatcher property, this is the one you should use to call methods on the control.

Changing the dispatcher in the call should work:

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);
                          }            
}

You could also store the Dispatcher of the UI thread in a field before executing the background action, but using the Dispatcher of the control better shows the intentions of the code: "I want to call this on whatever thread this control belongs to".

Update : I just realized that this is an instance method of your control, so the dispatcher instance you are using is the right one. So much for answering late in the night. Also, your code works for me, replacing your model by an IEnumerable. Is there something special in your model ?

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM