2013-11-22 60 views
0

我有相当多的编程知识,但这是我第一次在C#上的多线程应用程序上工作,所以我在寻求有关我的问题的帮助。C#从UI线程操纵线程

首先,代码,

public frmCEX() 
    { 
     InitializeComponent(); 
     refreshTicker(); 
    } 

    private void btnRefresh_Click(object sender, EventArgs e) 
    { 
     refreshTicker(); 
    } 

    private void refreshTicker() 
    { 
     ssStatus.Text = "Updating ticker.."; 
     btnRefresh.Text = "Updating"; 
     btnRefresh.Enabled = false; 
     ssUpdated.Text = "Last updated: -"; 

     APIManager apim = new APIManager(); 
     Ticker tk = apim.getTicker(); 

     //blablabla, do some work 

     ssUpdated.Text = "Last updated: " + DateTime.Now.ToString(); 
     ssStatus.Text = ""; 
     btnRefresh.Text = "Refresh"; 
     btnRefresh.Enabled = true; 
    } 

    private void cbxRefresh_CheckedChanged(object sender, EventArgs e) 
    { 
     if (cbxRefresh.Checked) 
     { 
      Thread thread1 = new Thread(() => BGRefreshThread(Convert.ToInt32(nupRefreshSecs.Value))); 
      thread1.Start(); 
     } 
     else 
     { 
      // IF REFRESH CHECKBOX IS UNCHECKED, STOP THE THREAD THAT IS REFRESHING 
     } 
    } 

    private void BGRefreshThread(int delay) 
    { 
     refreshTicker(); 
     System.Threading.Thread.Sleep(delay * 1000); 
    } 

我的主要问题是在cbxRefresh_CheckedChanged方法,基本上,这是如何工作的,当用户选中“自动刷新”复选框,在主界面中,的CheckedChanged方法将创建一个新线程BGRefreshThread,它在后台运行并刷新股票代码,一旦该复选框再次被取消选中,它将结束刷新股票代码的线程。

但是,一旦启动后,我遇到了结束该线程的问题,因为一旦checkedchanged方法结束,下一次未选中该复选框时,线程将不再存在于上下文中。

任何人都可以建议我可以得到这个工作吗?真的是新的多线程编程。

**编辑:我发现了这个问题的解决方案,但现在,当新创建的线程尝试调用“refreshTicker”更新主UI上的标签和按钮(主线程上) ,它给了我这个错误:

Cross-thread operation not valid: Control 'btnRefresh' accessed from a thread other than >the thread it was created on.

对此有何建议**

+0

将线程1存储在更高的范围内?使用信令,使用该任务库。 –

+0

您不能从UI线程以外的其他线程访问任何UI控件,您需要使用Control.Invoke或分派器。请参阅[这里](http://stackoverflow.com/questions/5037470/cross-thread-operation-not-valid)了解更多信息 –

+0

谢谢!我改变了“refreshTicker();”到“this.Invoke((MethodInvoker)委托(){refreshTicker();});”但股票仍似乎没有刷新,似乎线程没有运行,出于某种原因。 – InnovativeDan

回答

0

您需要保存线程在不超出范围的变量?

private Thread thread1; 

private void cbxRefresh_CheckedChanged(object sender, EventArgs e) 
    { 
     if (cbxRefresh.Checked) 
     { 
      thread1 = new Thread(() => BGRefreshThread(Convert.ToInt32(nupRefreshSecs.Value))); 
      thread1.Start(); 
     } 
     else 
     { 
      thread1.Abort(); 
     } 
    } 

请注意,有一些检查丢失和中止不是一个很好的方式来结束一个线程。

+0

你建议什么检查?什么是结束一个线程的适当方式? – InnovativeDan

+3

做*没有*使用'Thread.Abort()'! (http://stackoverflow.com/questions/710070/timeout-pattern-how-bad-is-thread-abort-really) –

+0

现在我有一个更大的问题,我更新了上面的问题与编辑,任何人都可以帮助我吗? – InnovativeDan

1

首先,线程变量应该是一个实例成员,因此您可以随时访问它。

我做正常停止线程是:在我创建并启动线程创建一个ManualResetEvent,我使用的信号线程退出:

private ManualResetEvent m_stopThread = new ManualResetEvent(false); 

要停止我设置了事件的线程地方在我的代码,并等待线程结束:

m_stopThread.Set(); 
m_myThread.Join(); 

线程的代码需要考虑停止:

while (true) 
{ 
    // Stop the thread if the handle is set after 1 ms 
    if (m_stopThread.WaitOne(1, false)) 
     break; 

    // Do some work 
} 
+0

现在我遇到了一个更大的问题,我通过编辑更新了上述问题,任何人都可以帮助我解决这个问题吗? – InnovativeDan

+0

您无法从任何其他线程访问UI线程上的组​​件。这已经在这里回答了数十亿次。使用'this.Invoke'(Windows窗体)或'this.Dispatcher.Invoke'(WPF)更改回UI线程。 –