C#获取原始线程以设置文本框值

时间:2012-03-22 17:43:45

标签: c# multithreading thread-safety

我的主要表单Form1正在运行我程序的主要部分。

我有一个单独的线程开始执行算法。

当我从新线程运行方法时,方法MyAlgorithm()我收到错误

  

InvalidOperationException,消息“控制控件名称是从创建它的线程以外的线程访问的。”

如何返回原始线程以便运行方法以使用最新值更新文本框?

这是我想要运行的方法,包含在我的应用程序中的主要类Form1中。

// Reset the results values
public void ShowResults()
{
    while (true)
    {

        loopsNum.Text = Convert.ToString(resultLoopsNum);
        nodesVisitedNum.Text = Convert.ToString(resultNodesVisitedNum);
        nodesResolvedNum.Text = Convert.ToString(resultNodesResolvedNum);
        cpuLoopsNum.Text = Convert.ToString(resultCpuLoopsNum);
        shortestPathCostNum.Text = Convert.ToString(resultShortestPathCost);

    } 
}

我查看了Invoke()方法,但我不知道如何从thread方法中获取Form1的原始实例。

我正在调用我的线程......

        // Set the algorithm method up in it's own thread
        Thread thread = new Thread(new ThreadStart(MyAlgorithm));

        // Run the algorithm
        thread.Start();

4 个答案:

答案 0 :(得分:5)

  

如何返回原始线程以便运行方法以使用最新值更新文本框?

在Windows窗体中,您使用Control.Invoke / BeginInvoke 使用BackgroundWorker并执行更新进度事件处理程序。

在WPF中,您使用Dispatcher.Invoke / BeginInvoke

在C#5和.NET 4.5中,您将能够使用异步方法,这样可以使这很简单......

  

我查看了Invoke()方法,但我不知道如何从thread方法中获取Form1的原始实例。

如果“线程方法”只是Form的实例方法,那么您已经获得了this引用。如果不是,您需要提供该信息 - 理想情况下为ISynchronizeInvoke,以避免直接依赖Windows窗体,如果您可以单独表达“更新”部分。 (现在这个界面有点被弃用,有利于同步上下文,但它仍然可以很好地运行。)

答案 1 :(得分:2)

查看Control.Invoke()

public void ShowResults()
{
  while (true)
  {
    Thread.Sleep(1000); // don't spam the UI thread

    if (this.InvokeRequired) 
    {
      this.Invoke((Action)UpdateGui);
    }  
    else
    {
      UpdateGui();
    }
  } 
}

private void UpdateGui() 
{  
  loopsNum.Text = Convert.ToString(resultLoopsNum);
  nodesVisitedNum.Text = Convert.ToString(resultNodesVisitedNum);
  nodesResolvedNum.Text = Convert.ToString(resultNodesResolvedNum);
  cpuLoopsNum.Text = Convert.ToString(resultCpuLoopsNum);
  shortestPathCostNum.Text = Convert.ToString(resultShortestPathCost);
}

答案 2 :(得分:1)

您可以使用:

myform.Invoke(ShowResults);

答案 3 :(得分:1)

这里还有其他选择:

或者使用System.Forms.Timer定期致电ShowResults。或者另一种选择是使用另一个线程来进行操作;当您想让GUI更新时,在GUI线程中执行此操作并从操作中调用Application.DoEvents()

第一个选项很好,因为它可以防止意外地使用Invoke个请求充斥GUI,第二个选项很好,因为它全部在GUI线程上,允许您对事物进行精细控制显示在GUI上。