我有一个工作线程抛出事件,这些事件由公共处理程序方法处理。实际上我想实现处理程序方法由创建包含抛出事件的工作线程的对象的线程执行。
我尝试了以下代码:
public partial class Form1 : Form
{
public event EventHandler Tested;
public Form1()
{
InitializeComponent();
Tested += new EventHandler(Form1_Tested);
}
private void Form1_Tested(object sender, EventArgs e)
{
Text = "Test";
}
private void Form1_Shown(object sender, EventArgs e)
{
#region Test 1
// Works normal in GUI-Thread directly
Form1_Tested(this, EventArgs.Empty);
#endregion
#region Test 2
// Works in worker thread and throws GUI exception
// because of foreign thread access
new Thread(new ThreadStart(delegate()
{
OnTested(EventArgs.Empty);
})).Start();
#endregion
#region Test 3
// Works in worker thread and returns to GUI-Thread
// to throw the event, so no need in eventhandler
// to use Control.Invoke();
AsyncOperation asyncOp = AsyncOperationManager.CreateOperation(null);
new Thread(new ThreadStart(delegate()
{
asyncOp.Post(new SendOrPostCallback(delegate(object obj)
{
OnTested(EventArgs.Empty);
}), null);
})).Start();
#endregion
}
protected virtual void OnTested(EventArgs e)
{
EventHandler tmpHandler = Tested;
if (tmpHandler != null)
tmpHandler(this, e);
}
}
我使用
看了一下线程Thread.CurrentThread.ManagedThreadId;
在启动工作线程之前,我的主线程的id是“1”。在UI线程内,恰好在触发事件之前,(工作线程的)线程ID是“4”。 现在仔细看看处理程序方法中的线程ID,线程ID就像“10” - 但我希望ID为“1”。 我很困惑。
一般来说:我的代码片段是正确的方法吗,或者这样做的最佳做法是什么(甚至是一个工作示例)?
我想避免在工作线程上实际使用Invoke。
此致 托马斯
答案 0 :(得分:1)
您可以使用任务<>而不是代表?我想如果可以的话,它可能会为你简化一些事情。
基本上,如果你创建一个Task<>,你可以通过访问.Result属性访问该任务的结果,该属性将等待线程完成,然后给你返回代码或 - 如果线程抛出异常 - 将在访问.Result属性的线程的上下文中重新抛出该异常。
(如果您的线程没有返回任何内容,您只需调用Task.Wait()而不是访问.Result)
有些代码可能有助于解释我的意思:
using System;
using System.Threading;
using System.Threading.Tasks;
namespace Demo
{
class Program
{
static void Main(string[] args)
{
var task = new Task<int>(() => test(1000, "Test1"));
tryTask(task);
task = new Task<int>(() => test(2000, "Test2"));
tryTask(task);
task = new Task<int>(() => test(1, "Test2"));
tryTask(task);
}
static void tryTask(Task<int> task)
{
task.Start();
try
{
Console.WriteLine("Task result = " + task.Result);
}
catch (AggregateException ex)
{
Console.WriteLine("Task threw an exception: " + ex.InnerException.Message);
}
}
static int test(int value, string name)
{
Console.WriteLine("Starting thread " + name);
Thread.Sleep(value);
Console.WriteLine("Ending thread " + name);
if (value == 1) // Magic number!
{
throw new InvalidOperationException("Test Exception");
}
return value;
}
}
}