WPF DependencyObject calling thread exception

1.4k views Asked by At

I have the following code which creates a temporary folder and uses a FileSystemWatcher to poll for files added to the folder on the Location property, and add them to a list: Scratchdisk.cs on Pastebin. The idea is to create a Scratchdisk object, and have FFmpeg extract video frames into it, the FileSystemWatcher builds a list of these files as FFmpeg creates them, and the list is presented as a DependencyObject that my UI binds to.

I'm binding to the Scratchdisk object like so:

<ItemsControl ItemsSource="{Binding Source=ThumbnailScratchdisk, Path=FileList}">
...
</ItemsControl>

On actually creating the object though, I get the following exception:

A first chance exception of type 'System.InvalidOperationException' occurred in WindowsBase.dll

Additional information: The calling thread cannot access this object because a different thread owns it.

on line 28 get { return (List<string>)GetValue(FileListProperty); }

I think I need a Dispatcher.Invoke somewhere but I have no idea where, I don't know where the second thread is being created. I'm assuming it has something to do with the FileSystemWatcher writing to the file list.

Any help?

Thanks!

3

There are 3 answers

2
Vladimir On

You can wrap your call inside an Action() being called from Dispatcher like this:

this.Dispatcher.BeginInvoke(new Action(() =>
{
    // your code accessing UI elements here
}));
1
Stubby On

Even though this is a fairly old thread, I wanted to give a hint to anyone who ran into the same thing I did. This is an intentionally verbose description so the search engines can find it for the next guy/gal who hits this obscure behaviour.

After getting the SetValue/GetValue compile error described here, I needed to derive my VM from a DependencyObject.

I wanted to continue deriving my VM from our ViewModelBase, which was derived from our AbstractNotifyPropertyChanged class (can't derive from 2 full classes in C#, of course). Being the super smart guy I am, I figured I would add the DependencyObject derivation to my AbstractNotifyPropertyChanged class. I couldn't see any reason why this little change would have any detrimental effects. For many weeks, the application was running fine.

There is always a big hairy "however". During testing, it was discovered that one of my comboboxes crashed the entire application when an item was selected. This was due to an unhandled InvalidOperationException. "The calling thread cannot access this object because a different thread owns it." The only thing that made this combobox different was the fact that it used DependencyProperty for some values.

Four days of frustrating debugging led nowhere because none of my code was making the call. It was all coming from WPF, and blowing up when the call stack reached VerifyAccess in GetValue. Obviously when it is being called by the framework, attempting to call Invoke to cross threads was not going to happen? Where would you put the Invoke call?

Since normal debugging failed, I had to go about it the hard way. I retraced my checkin steps to find the last time the code worked. I already had the idea that it was somehow related to the DependencyProperty of the combobox, so seeing the code changes, my suspicions pointed to the DependencyObject derivation.

After some finagling of the code derivations to remove DependencyObject from the chain for all of my ViewModels (through ViewModelBase), and placing that derivation only in the exact locations that I needed it, The problem has been solved.

0
DotNetRussell On

The way I access it is like this. It gets the UI Thread's Dispatcher

System.Windows.Application.Current.Dispatcher.Invoke(
  (Action)(() => 
  {
      //Access the UI from here 
  }));

The main thing to note here between what I have and what you have listed in the comments is that mine will work regardless if you're in the behind code, the view model, a service class, wherever. Not all items have a Dispatcher on them so this.Dispatcher doesn't always work.