1

我想在一个额外的线程中result执行后使(重进程的返回结果)可以访问Heavy Process,因为它主要是预期不希望在进程 UI 生效后,进程完成后可以玩result

在一些搜索过程中,查看我的文章,我发现有几种方法可以实现这一点,请提供您知道或在类似情况下使用的最佳方法

这是我想以最佳方法处理的示例:

        public ACollection DoProcess(Document docProcess) 
        {
            ACollection result = new ACollection ();

            ThreadStart threadStart = delegate
            {
                result = MyProcess(docProcess);
            };
            var threadProcess = new Thread(threadStart);
            threadProcess.Start();    

            return result ;
}

其他可能的方法可能是 IAsyncResult、BackgroundWorker、使用计时器和检查状态,而不是将结果返回给处理它的方法并将其报告给 UI,以线程安全的方式直接将其发送到我们的 UI 控件...

请在类似情况下给出您自己的意见和样品,在此先感谢

编辑 3:方法 - 基于布赖恩的回答

        LenzCollection myResultCollection = new LenzCollection();       

        TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();

        Task.Factory.StartNew(() =>
          {
              myResultCollection = DoCollect(docProcess);
              //Task.WaitAll();

              return myResultCollection;
          }).ContinueWith((task =>
          {
              myResultCollection = task.Result;
          }), ui);

        return myResultCollection;  

它仍然没有等待,也不会给出想要的结果

4

4 回答 4

2

只需实现一个事件,在执行方法之前注册它。并让该方法在完成后引发事件。

例如:

public delegate void MyEventHandler(string result);
public class MyClass
{
  public event MyEventHandler MyEvent;
  private void Event(string result)
  {
    MyEventHandler handler = MyEvent;
    if(handler != null)
      handler(result);
  }

  public void DoSomethingLong()
  {
    //Do something
    Event("Finish");
  }
}

现在你可以像这样运行

MyClass.Event += MyEventHandler(On_Event);
Thread t = new Thread(MyClass.DoSomethingLong);
t.Start();    

void On_Event(string result)
{
  //Get executed when finished;
}

调用 UI 线程的示例

void On_Event(string result)
{
  if(this.InvokeRequired)
  {
    MyEventHandler handler = new MyEventHandler(On_Event);
    Invoke(handler, new object[] { result });
    return;
  }
  // At this point you can access your UI without having Cross-Threaded operation!
}
于 2012-04-13T10:18:51.157 回答
2

在桌面 (WinForms/WPF) 应用程序中,最好和最简单的方法是 BackgroundWorker。它旨在处理这个问题。

于 2012-04-13T10:21:12.140 回答
1

如果您正在使用.NET Framework 4.0 or +,您可以从另一个线程运行该进程并在Task.ContinueWith中进行进程,例如

Process pro = null; 
 Task.Factory.StartNew(() => {
   pro =new Process(..);
   pro.Start(); 
   pro.WaitForExit(); 
}).ContinueWith(..process data recieved from the pro)

编辑

不使用while(...),但使用pro.WaitForExit()

希望这可以帮助。

于 2012-04-13T10:20:11.400 回答
1

选项1:

使用Task类和ContinueWith方法。

TaskScheduler ui = TaskScheduler.FromCurrentSynchronizationContext();

Task.Factory.StartNew(() =>
  {
    var result = MyProcess(docProcess);
    return result.ToString();
  }).ContinueWith((task =>
  {
    textBox1.Text = task.Result;
  }, ui);

您必须记住将正确的同步上下文传递到ContinueWith方法中。你可以看到我是如何使用ui变量做到这一点的。

选项#2:

使用 newasyncawait关键字。1

private async void SomeButton_Click(object sender, EventArgs args)
{
  textBox1.Text = await Task.Run(() =>
    {
      var result = MyProcess(docProcess);
      return result.ToString();
    });
}

显然,这在视觉上要容易得多,并且可以为您完成所有编组和同步上下文的工作。


1新关键字将在 C# 5.0 中可用,但您现在可以通过Async CTP使用它们。CTP 使用TaskEx而不是Task.

于 2012-04-13T13:31:21.190 回答