0

I want to call a method till it returns a value in my WPF app.

void btnDecode_Click(object sender, RoutedEventArgs e)
{
    var task = new Task(task);
    task.Start();
    task.Wait();
}

async void task()
{
    Task<object> result= DecodedResult((BitmapSource)imageBarcode.Source);
    object i = await result;
    txtBarcodeContent.Text = i.ToString();
}

async Task<object> DecodedResult(BitmapSource renderTargetBitmap)
{
    var reader = new BarcodeReader();
    txtBarcodeContent.Text = "reading";

    return reader.Decode(renderTargetBitmap);
}

But it throws me an error on task.Start();

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

Why can't I access it and why does another thread own it?

Paul Roub
  • 36,322
  • 27
  • 84
  • 93
John
  • 127
  • 1
  • 13
  • "it throws me error" doesn't say where it's failing - what is "it" here? Please be clearer. (It's also odd to have an `async` method and then start it as a new task explicitly. Why not just make it `async Task mjau` - or ideally with a better name...) – Jon Skeet Jun 04 '15 at 09:00
  • Also, please specify more context - is this a web-app? WinForm? – Jon Skeet Jun 04 '15 at 09:01
  • possible duplicate of [The calling thread cannot access this object because a different thread owns it.WPF](http://stackoverflow.com/questions/10795948/the-calling-thread-cannot-access-this-object-because-a-different-thread-owns-it) – weston Jun 04 '15 at 09:12
  • Just google with the exception message first. – helb Jun 04 '15 at 09:12
  • @MatíasFidemraizer if it asked thousand times... then show me clear answer and solution for this problem... I searched but didn't find any working solution for me. – John Jun 04 '15 at 09:13
  • @John Oh yeah, use the search function both in SO or Google. Look for *how to modify a control property from other thread than UI*... – Matías Fidemraizer Jun 04 '15 at 09:27

2 Answers2

1

Whenever you update your UI elements from a thread other than the main thread, you need to use:

this.Dispatcher.Invoke((Action)(() =>
{
       ...// your code here.
}));

You can also use control.Dispatcher.CheckAccess() to check whether the current thread owns the control. If it does own it, your code looks as normal. Otherwise, use above pattern.

Noam M
  • 3,156
  • 5
  • 26
  • 41
1

This is illegal from anywhere but the UI thread.

txtBarcodeContent.Text = i.ToString();

And task.Wait(); ruins the async effect.

Solution

You can have async on the click method.

This works: Note I only async when I await and I avoid async void (Using async without await).

private async void btnDecode_Click(object sender, RoutedEventArgs e)
{
    string result = await DecodedResult((BitmapSource)imageBarcode.Source);
    txtBarcodeContent.Text = result;
}

private async Task<string> DecodedResult(BitmapSource renderTargetBitmap)
{
    object decoded = await reader.Decode(renderTargetBitmap);
    return decoded.ToString();
}
Community
  • 1
  • 1
weston
  • 54,145
  • 21
  • 145
  • 203