我需要每5秒调用一次异步操作,因为操作有时可能会更长,我想出来调用方法,然后在我得到结果后等待5秒并再次调用它。
在大班我有类似的东西:
public partial class Form1 : Form
{
private Timer loopTimer;
public Form1()
{
InitializeComponent();
loopTimer = new Timer() { Interval = 10000 /*10 seconds*/};
loopTimer.Tick += loopTimer_Tick;
EWS.Instance.DoOperation(Operation_OK, Operation_ERROR);
}
private void Operation_OK(int count)
{
Console.WriteLine("timer start");
loopTimer.Start();
Console.WriteLine("timer enabled: " + loopTimer.Enabled);
Console.WriteLine("async result : " + count);
}
private void Operation_ERROR(string err)
{
MessageBox.Show(err);
}
private void loopTimer_Tick(object sender, EventArgs e)
{
Console.WriteLine("tick");
loopTimer.Stop();
EWS.Instance.DoOperation(Operation_OK, Operation_ERROR);
}
}
我的EWS课程如下所示:
class EWS : SingletonBase<EWS>
{
private EWS()
{
}
private int LongRunningMethod(Action<string> error)
{
Console.WriteLine("5 seconds operation");
Thread.Sleep(5000);
int unreadCount = 100;
return unreadCount;
}
public class CommandAndCallback<TSuccess, TError>
{
public TSuccess Success { get; set; }
public TError Error { get; set; }
public Func<Action<string>, int> Delegate { get; set; }
}
public void DoOperation(Action<int> success, Action<string> error)
{
Func<Action<string>, int> dlgt = LongRunningMethod;
CommandAndCallback<Action<int>, Action<string>> config = new CommandAndCallback<Action<int>, Action<string>>() { Success = success, Error = error, Delegate = dlgt };
dlgt.BeginInvoke(error, MyAsyncCallback, config);
}
public void MyAsyncCallback(IAsyncResult ar)
{
int s;
CommandAndCallback<Action<int>, Action<string>> config = (CommandAndCallback<Action<int>, Action<string>>)ar.AsyncState;
s = config.Delegate.EndInvoke(ar);
Console.WriteLine(s);
if (s > -1)
config.Success(s);
}
}
我可以调用我的方法异步,处理错误,但我不知道为什么我在5秒后无法再调用它。
致电loopTimer_Tick
后,我没有拨打{p> loopTimer.Start();
我重写了几次,每次都无法让定时器工作。
我需要在循环中调用方法(调用交换服务器),但在调用之间有时间间隔,如果有更好的方法可以这样做,请写:)
答案 0 :(得分:2)
System.Windows.Forms.Timer类不是线程安全的。这里的具体失败是你在线程池线程上调用它的Start()方法。这会创建一个隐藏窗口,提供Tick事件,但它是在错误的线程上创建的。一个不会引发消息循环,因此Tick事件永远不会被引发。
可能的解决方法是在主线程上调用Start(),例如在DoOperation()方法中。或者使用System.Timers.Timer,但要注意其Elapsed事件处理程序在任意线程池线程上运行,因此您无法直接从它访问UI。您应该对实际取消操作采取一些措施,如果您使用BackgroundWorker或Task类,这种代码往往会变得更简单。