我在将DispatcherTimer语法转换为线程计时器时遇到问题。当我突然运行我的应用程序时,它会关闭而没有任何错误。
基本上我希望计时器每5秒执行2个方法。
编辑:这两种方法正在更新用户界面。 我试图摆脱DispatcherTimer,因为我必须在UI显示中冻结和延迟。
Dispatcher计时器代码:
timerW = new DispatcherTimer();
timerW.Tick += new EventHandler(timerW_Tick);
timerW.Interval = new TimeSpan(0, 0, 5000);
timerW.Start();
private void timerW_Tick(object sender, EventArgs e)
{
DisplayWegingInfo();
CaculateTimen();
}
System.Threading Timer的代码:
public void InitializeDispatcherTimerW()
{
TimerCallback callback = MyTimerCallBack;
timerW = new Timer(callback);
timerW.Change(0, 5000);
}
private void MyTimerCallBack(object state)
{
DisplayWegingInfo();
CaculateTime();
}
感谢。
答案 0 :(得分:3)
最有可能的问题是您正在更新计时器回调中的方法中的UI。这只能从UI线程开始,而计时器在后台线程中运行。
我建议您坚持使用DispatcherTimer
。
另一种解决方案是将代码分解一下:将工作密集型代码解压缩到其他方法并在后台线程中运行,然后从UI线程更新UI。
这样的事情:
private void MyTimerCallBack(object state)
{
LongCalculationsThatDontNeedTheUI();
_dispatcherUIThread.Invoke(new Action(UpdateUI));
}
答案 1 :(得分:2)
根据名称DisplayWedgingInfo判断,我猜这个方法会更新UI吗? System.Threading.Timer在与UI线程不同的线程上执行,因此为了能够从该线程更新UI,您需要使用Dispatcher::[Begin]Invoke
将这些调用封送回Dispatcher
线程。
因此,您可以保留任何不会触及UI元素的昂贵工作,但对于UI操作,您只需执行以下操作:
string someValue = this.SomeExpensiveOperation();
this.Dispatcher.BeginInvoke(
DispatcherPriority.Background,
new Action(() =>
{
this.myControl.Text = someValue;
}));
我应该指出,在调用确实发生时,可能会发生任何UI交互/呈现的中断。这是不可避免的,因为执行将在主线程上发生。通过使用DispatcherPriority.Background
,您至少可以使用优先级来安排更新,该优先级使其低于用户当时可能提供的任何输入。但是,不要期望能够在没有任何惩罚的情况下对UI进行大规模更新。如果你需要这样做,最好排队多个Background
优先级的调用,以便它们可以发生更高优先级的事情,如必要时输入。
答案 2 :(得分:0)
我认为您需要将数据检索/计算与数据显示分开。
Daniel指出,任何GUI更新都需要在Dispatcher线程上完成,因此最简单的方法是使用DispatcherTimer
。
但是,使用DispatcherTimer
表示计时器回调中的所有在GUI线程中完成。如果您有任何需要花费大量时间的操作,这并不好。如您所见,GUI会断断续续并锁定。
你需要找出花时间的东西。从你的其他问题我猜它是SQL检索。在这种情况下,您最好在单独的线程上进行实际的检索(使用System.Threading.Timer
),一旦获得结果,请使用更新显示 Dispatcher.BeginInvoke()
编组到GUI线程。
答案 3 :(得分:0)
我会检查两件事: 1.正如其他人所说,确保如果您正在更新UI,那么您正在调用回调度程序 - 您只能从UI线程更新UI。即使您正在使用数据绑定 - 如果计时器线程更新了数据绑定到UI的值,那么“计数”为触摸UI的错误线程。
答案 4 :(得分:-3)
为什么不简单地使用后台线程来分派事件?
CancellationTokenSource cts = new CancellationTokenSource();
Task.Factory.StartNew(() =>
{
while(!cts.IsCancellationRequested)
{
Thread.Sleep(5000);
this.Dispatcher.BeginInvoke(new Action(() =>
{
DisplayWegingInfo();
CalculateTimen();
}), null);
}
});