This is my first question here. As English is not my first language, forgive me for any mistakes.
I'm trying to develop an application for Windows Phone 8.1 (XAML and C#) and I'm using .NET Framework 4.5.2. I just started studying multithreading in C# and would appreciate if anyone here could help me. All answers to related questions I've found so far are too complex.
All I need is to create a new task from a button click that displays a message in a textblock control.
private void myButton_Click(object sender, RoutedEventArgs e)
{
Task t = new Task(MyMethod);
t.Start();
}
private void MyMethod()
{
myTextBlock.Text = "Worked!";
}
I'm getting the following exception: The application called an interface that was marshalled for a different thread. (Exception from HRESULT: 0x8001010E (RPC_E_WRONG_THREAD)).
How can I correct this?
Thanks in advance!
Designer Code:
namespace Tasks
{
partial class Form1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.textBox1 = new System.Windows.Forms.TextBox();
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(41, 43);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(75, 23);
this.button1.TabIndex = 0;
this.button1.Text = "button1";
this.button1.UseVisualStyleBackColor = true;
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// button2
//
this.button2.Location = new System.Drawing.Point(131, 43);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(75, 23);
this.button2.TabIndex = 1;
this.button2.Text = "button2";
this.button2.UseVisualStyleBackColor = true;
this.button2.Click += new System.EventHandler(this.button2_Click);
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(41, 84);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(165, 20);
this.textBox1.TabIndex = 2;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(240, 151);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
private System.Windows.Forms.TextBox textBox1;
}
}
This is the form code:
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Tasks
{
public partial class Form1 : Form
{
//Just incase you need to stop the current task
CancellationTokenSource cts;
public Form1()
{
InitializeComponent();
}
private void button2_Click(object sender, EventArgs e)
{
//showing that the form is still working
MessageBox.Show(this,"This button still works :)");
}
private async void button1_Click(object sender, EventArgs e)
{
cts = new CancellationTokenSource();
await CreateTask();
}
private async Task CreateTask()
{
//Create a progress object that can be used within the task
Progress<string> mProgress; //you can set this to Int for ProgressBar
//Set the Action to a function that will catch the progress sent within the task
Action<string> progressTarget = ReportProgress;
//Your new Progress with the included action function
mProgress = new Progress<string>(progressTarget);
//start your task
string result = await MyProcess(mProgress);
MessageBox.Show(this, result);
}
//notice the myProgress this can be used within your task to report back to UI thread.
private Task<string> MyProcess(IProgress<string> myProgress)
{
return Task.Run(() =>
{
//here you will sen out to your UI thread whatever text you want.
//typically used for progress bar.
myProgress.Report("It Works..");
//your tasks return
return "Yes it really does work...";
}, cts.Token);
}
private void ReportProgress(string message)
{
//typically to update a progress bar or whatever
//this is where you Update your UI thread with text from within the Task.
textBox1.Text = message;
}
}
}
Basically what it you are doing is passing in a Progress that you can use with your task.
If you use the async/await programming model, you could do this quite easily.
Instead of what you have, try something like this:
private async void myButton_Click(object sender, RoutedEventArgs e)
{
Task t = MyMethod();
await t;
}
private async Task MyMethod()
{
myTextBlock.Text = "Worked!";
}
If you are inside a Windows Phone (WinRT, not Silverlight) Project you can also use
await CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(CoreDispatcherPriority.Normal, new DispatchedHandler(() =>
{
// your code
}));
User contributions licensed under CC BY-SA 3.0