我的目标:我有一个信用卡等待窗口。我将从客户端调用一个函数来等待信用卡刷卡。为了避免程序在等待信用卡时卡住。我正在使用委托来运行计时器。代表将拨打计时器。计时器定期检查卡的存在。如果它找到了一张卡,它将由客户分配一个回调/代表。
下面给出了代码,我的问题是 1)是否会在线程中调用_timer_Elapsed,以便为ui窗口增加最小的开销?
2)如何从timer函数调用基类的回调/事件。我编写了一个受保护的方法,它将调用基类中的事件/委托。我需要从timer函数调用protected方法(它在派生类的一个委托中。)?
Wait wait = delegate()
{
_timer = new Timer(3000); // Set up the timer for 3 seconds
_timer.Elapsed += new ElapsedEventHandler(_timer_Elapsed);
_timer.Enabled = true; // Enable it
static void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
// if(CheckCardsPresence())
{
//RaiseEvent()
//KillTimer()
}
//else
{
// do nothing. wait more
}
}
};
wait.Invoke();
答案 0 :(得分:1)
不,计时器回调将不在委托线程上执行。
当您使用System.Threading.Timer时,回调将被推送到Threadpool。
第二个问题(一次只试一个问题)
答案 1 :(得分:0)
来自MSDN documentation(抱歉我第一次上错了课程)
此Windows计时器专为使用UI线程执行处理的单线程环境而设计。它要求用户代码具有可用的UI消息泵。
这是一种迂回的说法,即在UI线程/消息泵上引发事件,即你的第一个问题的答案是肯定的,只要你的“线程”是指“UI线程”。 / p>
我真的不明白你的第二个问题 - 你在说什么基类?
答案 2 :(得分:0)
首先,该代码不会编译。您不能在另一个方法中声明命名方法。但是,您可以声明匿名方法或lambda表达式,然后将其分配给委托引用。
可能不需要对信用卡设备进行异步轮询。您可以使用System.Windows.Forms.Timer
并从在UI线程上运行的Tick
事件执行轮询。如果CheckCardsPresence
是一个快速操作,这是可以接受的。
public class CreditCardWaitWindow : Form
{
private System.Windows.Timer timer = new System.Windows.Timer();
private void Form_Load(object sender, EventArgs args)
{
timer.Tick += OnTick;
timer.Interval = 3000;
timer.Start();
}
private void OnTick(object sender, EventArgs args)
{
if (CheckCardsPresence())
{
RaiseEvent();
timer.Stop();
}
}
}
如果轮询信用卡设备是一项耗时的操作,那么您将需要在另一个线程上执行此操作以避免阻止UI。
public class CreditCardWaitWindow : Form
{
private System.Timers.Timer timer = new System.Timers.Timer();
private void Form_Load(object sender, EventArgs args)
{
timer.Elapsed += OnElapsed;
timer.Interval = 3000;
timer.AutoReset = false;
timer.Start();
}
private void OnElapsed(object sender, ElapsedEventArgs args)
{
if (CheckCardsPresence())
{
Invoke(
(MethodInvoker)(() =>
{
RaiseEvent();
}), null);
}
else
{
timer.Start();
}
}
}
以下是使用Task
的清洁实现。
public class CreditCardWaitWindow : Form
{
private void Form_Load(object sender, EventArgs args)
{
Task.Factory.StartNew(
() =>
{
while (true)
{
Thread.Sleep(3000);
if (CheckCardsPresence()) break;
}
}, TaskCreationOptions.LongRunning).ContinueWith(
() =>
{
RaiseEvent();
}, TaskScheduler.FromCurrentSychronizationContext());
}
}
最重要的是,您可以使用新的await
关键字在C#5.0 1 中执行此操作。我不确定它能不能再简洁了!
public class CreditCardWaitWindow : Form
{
private async void Form_Load(object sender, EventArgs args)
{
while (!CheckCardsPresence()) await Task.Delay(3000);
RaiseEvent();
}
}
1 C#5.0尚未发布。