2011-09-21 58 views
0
class ... 
{ 
    onClick() 
    { 
     while(true) 
     { 
     //call the thread from here 
     threadpool(request)//send request to thread using thread pool 
     } 
    } 

    //the function for thread 
    threadfunction()//function that thread calls 
    { 

    // I am not able to change the textbox/datagridview in windowsform from here the main ui gets stuck // 

    } 
} 

我不想改变上面的逻辑是有可能更新datagrid simaltaneously从线程的函数,因为我的程序只是卡住了。当从while循环调用线程时,窗体GUI会冻结。如何让Gui回应?

+1

请显示真实代码而不是您在此处显示的伪代码。阅读http://tinyurl.com/so-hints –

+0

我想我们需要看更多的代码才能诊断这个。 “线程的函数”实际上是如何写入的? –

回答

3

while (true)应该在threadfunction里面,而不是在onClick上。否则,GUI会卡住,因为它无休止地执行着while(true)

2

根据给定的代码while(true)永远运行。如果你有一个耗时的过程,你将不得不使用一个单独的线程来处理它。如果您在主线程(UI线程)中执行耗时的进程,它将很繁忙,并且不会考虑您的UI更改请求,直到完成该任务。这就是你遇到UI冻结的原因。

如果您使用backgroundWorker进行耗时的任务,您将能够实现您想要的效果。您必须执行BackgroundWorkder.DoWork方法中的while(true)子句中的逻辑。

约BackgroundWorker的几点......

的DoWork在不同的线程,报告进度,主线程和取消异步过程是BackgroundWorker的最重要的功能。下面的例子很清楚地展示了这三个功能。网上有很多可用的例子。

using System; 
using System.Threading; 
using System.ComponentModel; 

class Program 
{ 
    static BackgroundWorker _bw; 

    static void Main() 
    { 
    _bw = new BackgroundWorker 
    { 
     WorkerReportsProgress = true, 
     WorkerSupportsCancellation = true 
    }; 
    _bw.DoWork += bw_DoWork; 
    _bw.ProgressChanged += bw_ProgressChanged; 
    _bw.RunWorkerCompleted += bw_RunWorkerCompleted; 

    _bw.RunWorkerAsync ("Hello to worker"); 

    Console.WriteLine ("Press Enter in the next 5 seconds to cancel"); 
    Console.ReadLine(); 
    if (_bw.IsBusy) _bw.CancelAsync(); 
    Console.ReadLine(); 
    } 

    static void bw_DoWork (object sender, DoWorkEventArgs e) 
    { 
    for (int i = 0; i <= 100; i += 20) 
    { 
     if (_bw.CancellationPending) { e.Cancel = true; return; } 
     _bw.ReportProgress (i); 
     Thread.Sleep (1000);  // Just for the demo... don't go sleeping 
    }       // for real in pooled threads! 

    e.Result = 123; // This gets passed to RunWorkerCompleted 
    } 

    static void bw_RunWorkerCompleted (object sender, 
            RunWorkerCompletedEventArgs e) 
    { 
    if (e.Cancelled) 
     Console.WriteLine ("You canceled!"); 
    else if (e.Error != null) 
     Console.WriteLine ("Worker exception: " + e.Error.ToString()); 
    else 
     Console.WriteLine ("Complete: " + e.Result);  // from DoWork 
    } 

    static void bw_ProgressChanged (object sender, 
            ProgressChangedEventArgs e) 
    { 
    Console.WriteLine ("Reached " + e.ProgressPercentage + "%"); 
    } 
} 

查看here了解更多详情。

0

我会假设主(gui)线程由于循环而冻结(不清楚你是否以某种方式处理事件)。此外,要从另一个线程中更改gui,您必须调用Invoke并使用委托更改所需的值。

0

Windows窗体控件无法直接从单独的线程访问。您可能想要使用Control.Invoke更改文本框/数据视图属性
检出MSDN article.有关从单独的线程访问控件。

2

首先,不要在回调中产生无限循环,因为UI线程将永远运行该循环。然后,如果threadfunction()需要UI更新,您必须在代码重新同步到UI线程:

threadfunction() 
{ 
myControl.Update(result); 
} 

class TheControl 
{ 
public void Update(object result) 
{ 
    if (this.InvokeRequired) 
    this.Invoke(new Action<object>(Update), result); 
    else 
    { 
    // actual implementation 
    } 
} 
} 
0

考虑使用异步等待处理输入和而你的UI线程执行其他任务更新的结果。

事件处理程序:

private async void OnButton1_clicked(object sender, ...) 
{ 
    var result = await ProcessInputAsync(...) 
    displayResult(result); 
} 

假设ProcessInputAsync是耗时的功能。 DisplayResult由UI线程调用,并且可以正常处理。

注意:所有异步函数都应该返回Task而不是void或任务<Tresult>而不是TResult。有一个例外:异步事件处理程序应该返回void而不是Task。

private async Task<TResult> ProcessInputAsync(...) 
{ 
    return await Task.Run(() => LengthyProcess(...) 
} 

private TResult LengthyProcess(...) 
{ 
    // this is the time consuming process. 
    // it is called by a non-ui thread 
    // the ui keeps responsive 
    TResult x = ... 
    return x; 
} 

如果你真的不想等待了漫长的过程来完成,但你想要的是一个不同的线程更新你得到一个运行时错误,一个线程没有创建用户界面UI元素尝试更新它。为此我们有调用模式:

private void UpdateMyTextBox(string myTxt) 
{ 
    if (this.InvokeRequired) 
    { // any other thread than the UI thread calls this function 
     // invoke the UI thread to update my text box 
     this.Invoke(new MethodInvoker(() => this.UpdateMyTextBox(myTxt)); 
    } 
    else 
    { 
     // if here: this is the UI thread, we can access the my text box 
     this.TextBox1.Text = myTxt; 
    } 
}