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())
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()
.
If the IsReaderArrived
check is an instant non-blocking call (i.e., it takes less than ~50ms to complete), I'd suggest to start the polling loop on the caller's thread, using Task.Delay(interval)
:
public async Task StartMonitoring(int interval, CancellationToken token)
{
this.establishContext();
while (true)
{
token.ThrowIfCancellationRequested();
if (IsReaderArrived())
{
// make sure to reset the flag inside IsReaderArrived
// so the event won't be fired upon the next iteration
if (this.CardArrived != null)
this.CardArrived(this, EventArgs.Empty);
}
await Task.Delay(interval);
}
}
This is an asynchronous loop. If StartMonitoring
is called from a UI thread, the CardArrived
event will be fired on the same UI thread and the client of your code won't have to worry about Dispatcher.BeginInvoke
. If you need an explanation of how this is happening, read "It's All About the SynchronizationContext."
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With