why*_*heq 21 .net c# multithreading timer winforms
与计时器一起玩.上下文:带有两个标签的winforms.
我想知道如何System.Timers.Timer工作,所以我没有使用Forms计时器.我知道表单和myTimer现在将在不同的线程中运行.是否有一种简单的方法来表示lblValue以下表格中的经过时间?
我在MSDN上看过这里,但有更简单的方法!
这是winforms代码:
using System.Timers;
namespace Ariport_Parking
{
public partial class AirportParking : Form
{
//instance variables of the form
System.Timers.Timer myTimer;
int ElapsedCounter = 0;
int MaxTime = 5000;
int elapsedTime = 0;
static int tickLength = 100;
public AirportParking()
{
InitializeComponent();
keepingTime();
lblValue.Text = "hello";
}
//method for keeping time
public void keepingTime() {
myTimer = new System.Timers.Timer(tickLength);
myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);
myTimer.AutoReset = true;
myTimer.Enabled = true;
myTimer.Start();
}
void myTimer_Elapsed(Object myObject,EventArgs myEventArgs){
myTimer.Stop();
ElapsedCounter += 1;
elapsedTime += tickLength;
if (elapsedTime < MaxTime)
{
this.lblElapsedTime.Text = elapsedTime.ToString();
if (ElapsedCounter % 2 == 0)
this.lblValue.Text = "hello world";
else
this.lblValue.Text = "hello";
myTimer.Start();
}
else
{ myTimer.Start(); }
}
}
}
Run Code Online (Sandbox Code Playgroud)
Adr*_*tti 35
我想你的代码只是一个测试,所以我不会讨论你用你的计时器做什么.这里的问题是如何使用计时器回调中的用户界面控件执行某些操作.
大多数Control的方法和属性只能从UI线程访问(实际上它们只能从你创建它们的线程访问,但这是另一个故事).这是因为每个线程必须有自己的消息循环(GetMessage()按线程过滤掉消息)然后用Control你必须从你的线程向主线程发送消息.在.NET中它很容易,因为每个Control方法都为此目的继承了几种方法:Invoke/BeginInvoke/EndInvoke.要知道执行线程是否必须调用那些具有该属性的方法InvokeRequired.只需使用此代码更改代码即可使其正常工作:
if (elapsedTime < MaxTime)
{
this.BeginInvoke(new MethodInvoker(delegate
{
this.lblElapsedTime.Text = elapsedTime.ToString();
if (ElapsedCounter % 2 == 0)
this.lblValue.Text = "hello world";
else
this.lblValue.Text = "hello";
}));
}
Run Code Online (Sandbox Code Playgroud)
请检查MSDN对于您可以从任何线程调用的方法列表中,只是作为参考,你可以随时调用Invalidate,BeginInvoke,EndInvoke,Invoke方法和读取 InvokeRequired性能.通常,这是一种常见的使用模式(假设this是从中派生的对象Control):
void DoStuff() {
// Has been called from a "wrong" thread?
if (InvokeRequired) {
// Dispatch to correct thread, use BeginInvoke if you don't need
// caller thread until operation completes
Invoke(new MethodInvoker(DoStuff));
} else {
// Do things
}
}
Run Code Online (Sandbox Code Playgroud)
请注意,当前线程将阻塞,直到UI线程完成方法执行.如果线程的时间很重要,这可能是一个问题(不要忘记UI线程可能忙或挂了一点).如果您不需要方法的返回值,您可以简单地替换Invoke为BeginInvoke,对于WinForms,您甚至不需要后续调用EndInvoke:
void DoStuff() {
if (InvokeRequired) {
BeginInvoke(new MethodInvoker(DoStuff));
} else {
// Do things
}
}
Run Code Online (Sandbox Code Playgroud)
如果你需要返回值,那么你必须处理通常的IAsyncResult接口.
GUI Windows应用程序基于窗口过程及其消息循环.如果你用普通的C编写一个应用程序,你会有这样的事情:
MSG message;
while (GetMessage(&message, NULL, 0, 0))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
Run Code Online (Sandbox Code Playgroud)
使用这几行代码,您的应用程序会等待消息,然后将消息传递给窗口过程.窗口过程是一个很大的开关/ case语句,你可以检查WM_你知道的消息()并以某种方式处理它们(你为窗口绘制WM_PAINT,退出应用程序WM_QUIT等等).
现在假设你有一个工作线程,你怎么能打电话给你的主线程?最简单的方法是使用这个底层结构来完成这个技巧.我过度简化了任务,但这些步骤是:
WPF和WinForms都使用此方法将消息从线程传递(分派)到UI线程.有关多线程和用户界面的更多详细信息,请查看MSDN上的这篇文章,WinForms隐藏了很多这些细节,您不必处理它们,但您可能需要了解它是如何工作的.
就个人而言,当我在一个使用UI中的线程的应用程序中工作时,我通常会写这个小片段.
private void InvokeUI(Action a)
{
this.BeginInvoke(new MethodInvoker(a));
}
Run Code Online (Sandbox Code Playgroud)
当我在不同的线程中执行异步调用时,我总是可以使用回调.
InvokeUI(() => {
Label1.Text = "Super Cool";
});
Run Code Online (Sandbox Code Playgroud)
简单干净.
| 归档时间: |
|
| 查看次数: |
73032 次 |
| 最近记录: |