我已经开始在c#中使用线程,但现在需要帮助,这是我的代码:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
DoCount();
}
public void DoCount()
{
for (int i = 0; i < 100; i++)
{
objTextBox.Text = i.ToString();
Thread.Sleep(100);
}
}
}
它是一个带文本框的简单胜利形式,我希望看到“计数”,但正如你在我的代码中看到的那样,文本框显示99,它计数到99然后显示...我会想,我必须在一个新的线程中管理这个,但不知道如何!
答案 0 :(得分:8)
使用BackgroundWorker。 MSDN上有一个BackgroundWorker overview。
以下是代码外观的示例:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
BackgroundWorker backgroundWorker = (BackgroundWorker)sender;
for (int i = 0; i < 100; i++)
{
backgroundWorker.ReportProgress(i);
Thread.Sleep(100);
}
}
private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
textBox1.Text = e.ProgressPercentage.ToString();
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker1.RunWorkerAsync();
}
}
其他说明:
答案 1 :(得分:7)
这可能就是你要找的东西:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
DoCount();
}
public void DoCount()
{
Thread t = new Thread(new ThreadStart(delegate
{
for (int i = 0; i < 100; i++)
{
this.Invoke((Action) delegate { objTextBox.Text = i.ToString(); });
Thread.Sleep(1000);
}
}));
t.IsBackground = true;
t.Start();
}
}
备注强>
答案 2 :(得分:1)
您可能需要尝试使用SynchronizationContext来执行此操作。
这是一个简短的例子,我把它们扔了一会儿:
public partial class Form1 : Form
{
private SynchronizationContext c;
private Thread t;
private EventWaitHandle pause =
new EventWaitHandle(false, EventResetMode.ManualReset);
public Form1()
{
this.InitializeComponent();
this.c = SynchronizationContext.Current;
}
private void Form1Activated(object sender, EventArgs e)
{
this.t = new Thread(new ThreadStart(delegate
{
this.pause.Reset();
while (this.t.IsAlive && !this.pause.WaitOne(1000))
{
this.c.Post(
state => this.label1.Text = DateTime.Now.ToString(),
null);
}
}));
this.t.IsBackground = true;
this.t.Start();
}
private void Form1Deactivate(object sender, EventArgs e)
{
this.pause.Set();
this.t.Join();
}
/// <summary>
/// Button1s the click.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
private void Button1Click(object sender, EventArgs e)
{
this.Close();
}
}
答案 3 :(得分:1)
您根本不需要线程来执行此类操作 - 请考虑将代码更改为事件驱动并使用System.Windows.Forms.Timer对象来实现您的计时。使用计时器有一个巨大的优势 - 它不需要1MB内存(一个线程),而且你不需要同步它们 - windows会为你做。
答案 4 :(得分:0)
请勿直接致电DoCount
,请致电ThreadPool.QueueUserWorkItem(DoCount)
。这将在新线程中运行DoCount。 (还有其他方法也可以,但这是最简单的方法。)
下一个问题是您无法直接从线程设置文本框。
要解决此问题,请使用类似于以下的代码:
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
有关完整示例,请参阅http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx。
答案 5 :(得分:0)
在Thread.Sleep之后,试试这个:
this.Update();
答案 6 :(得分:0)
我的解决方案与马克的解决方案几乎相同。唯一的区别是我在ProgressChanged事件中检查InvokeRequired。这是我的示例代码:
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace tester
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
if (!backgroundWorker1.IsBusy)
backgroundWorker1.RunWorkerAsync();
}
/// <summary>
/// This delegate enables asynchronous calls for setting the text property on a control.
/// </summary>
delegate void SetTextCallback(string status);
private void BackgroundWorker1DoWork(object sender, DoWorkEventArgs e)
{
for (var i = 0; i < 100; i++)
{
backgroundWorker1.ReportProgress(i);
Thread.Sleep(100);
}
}
private void BackgroundWorker1ProgressChanged(object sender, ProgressChangedEventArgs e)
{
if (label1.InvokeRequired)
Invoke(new SetTextCallback(SetLabelText), new object[] { e.ProgressPercentage.ToString()});
else
SetLabelText(e.ProgressPercentage.ToString());
}
private void SetLabelText(string text)
{
label1.Text = text;
}
}
}
答案 7 :(得分:0)
多线程可以解决这个问题,但对于像这个计数器这样简单的东西,它是不必要的。
另一位用户推荐了this.Update()。这可以使数字显示,因为UI将重绘自身。但它没有解决窗口没有响应的事实(你无法移动它)。
第三个解决方案和我对这个特定程序的建议是Application.DoEvents()。这样做是告诉底层本机窗口在消息池上执行其ProcessMessages方法。消息池包含Windows在需要重新绘制窗口,移动鼠标,移动窗体,最小化等窗口时发送给它的事件消息。这些指令由Windows发送并已排队。问题是程序在UI空闲之前不会处理它们。您可以通过调用此方法强制它。
Application.DoEvents()将产生一个窗口,该窗口以100 ms的间隔响应预期。它可能有点不稳定(线程会更敏感)但是它很容易放入并且通常就足够了。
for (int i = 0; i < 100; i++)
{
objTextBox.Text = i.ToString();
Application.DoEvents();
Thread.Sleep(100);
}
答案 8 :(得分:0)
以下是一个简单示例:
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Action countUp = this.CountUp;
countUp.BeginInvoke(null, null);
}
private void CountUp()
{
for (int i = 0; i < 100; i++)
{
this.Invoke(new Action<string>(UpdateTextBox), new object[] { i.ToString() });
Thread.Sleep(100);
}
}
private void UpdateTextBox(string text)
{
this.textBox1.Text = text;
}
}