Search code examples
c#.netwpfmultithreadingdispatcher

Different thread owns it in WPF


This is a UserControl that I am using.

this.CardHolderName.Content is a label that is in the UI of the user control.

public partial class PersonCredential : UserControl
        {
            public PersonCredential()
            {
                InitializeComponent();

                Dispatcher.BeginInvoke( (Action) (() => {
                        SCLib type = new SCLib();
                        type.StartMonitoring();

                        type.CardArrived += (string ATR) => { this.CardHolderName.Content = ATR; };
                    };
               }));

I am still getting the error , "The calling thread cannot access this object because a different thread owns it" even though I am using Dispatcher.BeginInvoke.

Is there something wrong in the way the Dispatcher is used ? }

EDIT: I am instantiating that user control inside a content control and the code-behind is:

public partial class MainWindow : Window
    {
       PersonCredential personCredential {get;set;}

        public MainWindow()
        {

            InitializeComponent();
            var personCredential = new CoffeeShop.PersonCredential();
            //create an instance of user control.
            this.personCredentials.Content = personCredential;
            // assign it to the content control inside the wpf main window
            .. // blah blah
        } 

EDIT 1:

Code for start-Monitoring:

public async void StartMonitoring()
        {

            // Wait for user to press a key

            try
            {
                this.establishContext();

                await Task.Run(new Action(WaitForReaderArrival));
                ////WaitForReaderArrival();

                if (IsReaderArrived())

Solution

  • EDIT from @DanPuzey's comments. StartMonitoring already monitors on another thread. The key is that the CardArrived event is not being raised from the UI thread:

    public PersonCredential()
    {
        InitializeComponent();
    
        SCLib type = new SCLib();
        type.StartMonitoring();
    
        type.CardArrived += (string ATR) => { 
            // when card arrives, dispatch back to UI thread
            Dispatcher.BeginInvoke(new Action(() => {
                this.CardHolderName.Content = ATR; 
            }));
        };
    }
    

    And if you are using .NET 4 or higher, use Task.Factory.StartNew() instead of new Thread().