2

You cannot bind to a WPF DataGrid's Columns property, so a workaround is to use use an attached property as found in this SO question/answer. My viewmodel exposes an ObservableCollection containing the DataGridColumns, and I bind it to the DataGrid via this attached property.

A background thread is responsible for populating the collection, and I'm using Dispatcher.Invoke to do this, which I thought would avoid threading issues. The background thread itself works fine, but an exception is raised in the above attached property code:

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

(in the else if that deals with an Add action, specifically the line dataGrid.Columns.Add(column);).

Any idea what might be wrong?

Community
  • 1
  • 1
Andrew Stephens
  • 9,413
  • 6
  • 76
  • 152
  • See this question: http://stackoverflow.com/questions/7687000/fast-performing-and-thread-safe-observable-collection – WildCrustacean Jan 30 '13 at 17:21
  • Could you build the ObservableCollection in the background. But then on the main (UI) thread add the columns? – paparazzo Jan 30 '13 at 17:33
  • @Blam not sure I follow. The ObservableCollection *is* my collection of columns. I'm using MVVM and this attached property is the only way to bind the columns at runtime (I don't know what columns I need at design-time so can't create them in XAML). The background thread performs a number of tasks - retrieves data, populates a collection to bind to the grid rows, and populates the columns collection. As a last resort I could move this last step out of the background thread and into the UI thread. Creating a dozen items doesn't warrant it being in a background thread. – Andrew Stephens Jan 30 '13 at 18:42
  • If creating a dozen items does not warrant being on a background thread then why is it a "last resort". What part don't you follow? – paparazzo Jan 30 '13 at 19:20

1 Answers1

1

If you are using .NET 4.5, the simplest option is to use BindingOperations.EnableCollectionSynchronization. This allows you to update a collection on a background thread directly, without worrying about synchronization in the binding.

Otherwise, you need to make sure that all changes to your collection happen on the user interface thread. Using Dispatcher.Invoke should work (provided you get the correct Dispatcher instance), though there are more elegant solutions, such as the binding collections in The Helper Trinity and other projects.

Reed Copsey
  • 554,122
  • 78
  • 1,158
  • 1,373
  • I'm using 4.0. I think I'm using the correct Dispatcher instance. If I put a breakpoint in the code and look at the Dispatcher's Thread.ManagedThreadID, it's the same as the main thread's ID. Similarly when the exception is raised, the thread window is showing as being in the main thread. Not sure what else I can check to confirm that I'm on the right threads everywhere. – Andrew Stephens Jan 30 '13 at 18:36
  • @AndrewStephens Make sure that your collection and the binding was *created* on the main UI thread, too... – Reed Copsey Jan 30 '13 at 18:58
  • Marked as answer as it was almost there, and inspired me to find the problem! Although I was adding my DataGridColumn objects to the ObservableCollection using Dispatcher.Invoke, I wasn't *creating* them using a Dispatcher, i.e. they were "owned" by the background thread - hence the exception message. – Andrew Stephens Jan 31 '13 at 08:25