Asked  7 Months ago    Answers:  5   Viewed   36 times

A common exception one can get when working with multiple threads in WPF is:

The calling thread cannot access this object because a different thread owns it

What are the options to deal with this properly?

 Answers

65

Depending on the situation there are various options:

Accessing a control from another thread

e.g. updating a TextBlock with progress information.

  • Data Binding:

    In this case the easiest thing you can do is avoiding the direct interaction with the control. You can just bind the property you want to access or modify to an object whose class implements INotifyPropertyChanged and then set the property on that object instead. The framework will handle the rest for you. (In general you rarely should need to interact with UI-elements directly, you can almost always bind the respective properties and work with the binding source instead; one case where direct control access may be necessary is control authoring.)

    There are some cases where data binding alone is not enough, for example when trying to modify a bound ObservableCollection<T>, for this you need...

  • Dispatching:

    You can dispatch your accessing code to the thread owning the object, this can be done by calling Invoke or BeginInvoke on the Dispatcher owning the object being accessed (getting this Dispatcher is possible on another thread).

    e.g.

    new Thread(ThisThreadStart).Start();
    
    void ThisThreadStart()
    {
        textBlock.Dispatcher.Invoke(new Action(() => textBlock.Text = "Test"));
    }
    

    If it is not clear on which thread a method is executed you can use Dispatcher.CheckAccess to either dispatch or execute an action directly.

    e.g.

    void Update()
    {
        Action action = () => myTextBlock.Text = "Test";
        var dispatcher = myTextBlock.Dispatcher;
        if (dispatcher.CheckAccess())
            action();
        else
            dispatcher.Invoke(action);
    }
    

    If an object is not a DispatcherObject and you still need the associated Dispatcher you can use Dispatcher.CurrentDispatcher in the thread creating the object (so doing this in the method being executed by a thread will not do you any good). For convenience as you usually create objects on the application's main UI thread; you can get that thread's Dispatcher from anywhere using Application.Current.Dispatcher.

Special cases:

  • BackgroundWorker

    Move any control access to ProgressChanged as it occurs on the thread that created the instance (which should of course be the UI-thread)

  • Timers

    In WPF you can use the DispatcherTimer for convenience, it does the dispatching for you so any code in Tick is invoked on the associated dispatcher. If you can delegate the dispatching to the data binding system you of course can use a normal timer as well.

You can read more about how the Dispatcher queue works and WPF threading in general on MSDN.

Accessing an object created on another thread

e.g. loading an image in the background.

If the object in question is not Freezable you should in general simply avoid creating it on another thread or restricting access to the creating thread. If it is Freezable you just need to call Freeze to make it accessible to other threads.

Accessing a data object from another thread

That is, the type whose instance is being updated is user-code. If an exception is thrown this situation probably came about by someone using DependencyObject as base type for a data class.

This situation is the same as accessing a control and the same approaches can be applied but usually it should be avoided in the first place. Granted, this allows for simple property change notifications via dependency properties and those properties can also be bound but often enough this is just not worth giving up thread-independency. You can get change notifications from INotifyPropertyChanged and the binding system in WPF is inherently asymmetrical, there always is a property that is bound (target) and something that is the source for this binding. Usually the UI is the target and the data is the source, meaning that only UI components should need dependency properties.

Tuesday, June 1, 2021
 
nighter
answered 7 Months ago
54

Below is some code I wrote for another SO question.
It requires the 3rd-party pyodbc module.

This very simple example will connect to a table and export the results to a file.
Feel free to expand upon your question with any more specific needs you might have.

import csv, pyodbc

# set up some constants
MDB = 'c:/path/to/my.mdb'
DRV = '{Microsoft Access Driver (*.mdb)}'
PWD = 'pw'

# connect to db
con = pyodbc.connect('DRIVER={};DBQ={};PWD={}'.format(DRV,MDB,PWD))
cur = con.cursor()

# run a query and get the results 
SQL = 'SELECT * FROM mytable;' # your query goes here
rows = cur.execute(SQL).fetchall()
cur.close()
con.close()

# you could change the mode from 'w' to 'a' (append) for any subsequent queries
with open('mytable.csv', 'w') as fou:
    csv_writer = csv.writer(fou) # default field-delimiter is ","
    csv_writer.writerows(rows)
Wednesday, July 28, 2021
 
DaveRandom
answered 5 Months ago
58

(And yes I did look at the code of the library method, and can get some idea of what exceptions are raised but I cannot be 100% sure and if it is not documented I feel uncomfortable relying on it.)

I suggest having a look at the tests, as they will show some of the "likely" scenarios and what might be raised. Don't forget that good tests are documentation, too.

Tuesday, August 3, 2021
 
Shurmajee
answered 4 Months ago
52

I usually use Application.Current.Dispatcher: since Application.Current is static, you don't need a reference to a control

Sunday, August 8, 2021
 
max_
answered 4 Months ago
77

All you're doing is creating a new object on another thread. After you create the object, the thread completes execution and becomes idle.

Object instances don't "live" on threads. An instance is just a pointer to a structure in memory. Just because you create an instance in thread A doesn't mean that all methods in that instance will run on thread A.

What you want to do is create a class that you can call from any thread but which uses its own internally managed thread (or some such construct) to perform execution.

Your "manager" should encapsulate a thread, or use the ThreadPool, to perform your "processing." When done, the manager will have to communicate back to your UI (using the Dispatcher to marshall this communication back onto the UI thread) indicating it has completed execution.

Friday, October 22, 2021
 
Luillyfe
answered 2 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share