-1

Trying to access WPF Controls from another thread is leading into 'System.InvalidOperationException' (cross thread access violation). The Description of the exception says, that the accessed object is not owned by the calling thread.

The following code shows that the 'System.InvalidOperationException' is not thrown when the second thread is accessing an non WPF-Control Object. But Why ?

How can I identify which Object is owned by which thread to avoid this exception ?

namespace Threading {
    
    public class TestObject {
        public Object Data { get; set; }
    }
    
    public partial class MainWindow : Window {
        TestObject _toOwnedByUI;     
        TextBox _txtOwnedByUI;
        BackgroundWorker _bw;

        public MainWindow () {
            InitializeComponent ();
            _bw = new BackgroundWorker ();
            _txtOwnedByUI = OutputBox;
            _bw.DoWork += onBwDoWork;
        }

        private void Button_Click (object sender, RoutedEventArgs e) {
            // initvalues from UI-Thread
            _toOwnedByUI = new TestObject () { Data = "UI Thread INIT" };
            _txtOwnedByUI.Text = "UI Thread INIT";
            // Start Second Thread
            _bw.RunWorkerAsync ();
        }

        // -------------------------------------------------------------------------         
        private void onBwDoWork(Object Sender, DoWorkEventArgs e) {
            // Change Values of testobjects by Second Thread
            _toOwnedByUI.Data = "Changed by BW-Thread";
            _txtOwnedByUI.Text = "Changed by BW-Thread";        // <----- throws System.InvalidOperationException : Invalid Thread
        }
    }
}
MaMe
  • 235
  • 1
  • 7

1 Answers1

1

Associating objects with threads is a WPF concept - it is NOT something that applies to all objects.

Every WPF object is derived from DispatcherObject which associates itself with the dispatcher of the current thread.

Later on, all operations on this objects are manually protected from cross thread calls with a call to VerifyAccess() which throws exception if the calling thread is different than the "owner" thread.

https://referencesource.microsoft.com/#WindowsBase/Base/System/Windows/Threading/DispatcherObject.cs,85082c8bba6e8038

For example, you can accomplish same behavior in your TestObject class by deriving from the DispatcherObject and protecting the Data property getter and setter with VerifyAccess().

At the end, you assumption that TestObject _tbOwnedByUI is owned by UI thread is wrong, there is no such concept/behavior for objects by default. That pretty much answers the questions.

Dusan
  • 5,000
  • 6
  • 41
  • 58