Reputation: 79
I've made a program that creates a thread and in that thread create image:
private async void GetCamera()
{
....
tk = new Task(MyAwesomeTask);
tk.Start();
}
private async void MyAwesomeTask()
{
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(0.5));
SavePhoto1();
}
}
private void SavePhoto1()
{
try
{
WriteableBitmap wb1 = new WriteableBitmap(320, 240);//throw exception
}catch (Exception ee)
{
String s = ee.ToString();
}
}
But line
WriteableBitmap wb1 = new WriteableBitmap(320, 240);
throws exception:
s="System.Exception: The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD))\r\n at Windows.UI.Xaml.Media.Imaging.WriteableBitmap..ctor(Int32 pixelWidth, Int32 pixelHeight)\r\n at TestVideo.MainPage.SetImageFromStream() in ...\MainPage.xaml.cs:line 500\r\n at TestVideo.MainPage.SavePhoto1() in ....\MainPage.xaml.cs:line 145"
What I need to do?
Upvotes: 1
Views: 1476
Reputation: 18803
The first problem is that you are using async void
. The only time that you should do this is when the method is an event handler. In your case, you should use async Task
instead:
private async Task GetCamera()
{
....
//tk = new Task(MyAwesomeTask);
//tk.Start();
await Task.Run(async () => await MyAwesomeTask());
...
}
private async Task MyAwesomeTask()
{
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(0.5));
// added await
await SavePhoto1();
}
}
You do not actually need to return a Task
in the above methods. The compiler automagically does that for you.
To address your question, you should only create WriteableBitmap
objects on the UI thread. You can do so with this:
private async Task SavePhoto1()
{
try
{
WriteableBitmap wb1 = null;
await ExecuteOnUIThread(() =>
{
wb1 = new WriteableBitmap(320, 240);//throw exception
});
// do something with wb1 here
wb1.DoSomething();
}catch (Exception ee)
{
String s = ee.ToString();
}
}
public static IAsyncAction ExecuteOnUIThread(Windows.UI.Core.DispatchedHandler action)
{
return Windows.ApplicationModel.Core.CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, action);
}
I didn't test the above by compiling it, but it should give you a good start. Let me know if you have questions.
Upvotes: 4