我的应用程序中有一些指标。有时,当UI忙时,我的仪表线程会停止等待更新某些仪表。在那种情况下,我想简单地放弃我的计划,并尝试在下一次民意调查中更新指标。我目前使用Control.Invoke从我的数据轮询线程移动到UI。我不想使用BeginInvoke,因为我不想浪费宝贵的UI时间更新仪表,因为它只是重要的最终值。有没有其他方法可以在UI线程上调用代码,如果我无法在40ms内进入UI线程,我可以提前纾困?是否需要Invoke方法中的代码,或者是否有其他方法可以在主线程上调用方法?
答案 0 :(得分:3)
没有可用的超时选项。一种选择是使用BeginInvoke
,但前提是已经处理了上一条消息。这将需要线程同步,但可以类似于:
// using
object syncObj = new object();
bool operationPending = false;
while (operation)
{
// ... Do work
// Update, but only if there isn't a pending update
lock(syncObj)
{
if (!operationPending)
{
operationPending = true;
control.BeginInvoke(new Action( () =>
{
// Update gauges
lock(syncObj)
operationPending = false;
}));
}
}
}
// Update at the end (since you're last update might have been skipped)
control.Invoke(new Action(UpdateGuagesCompleted));
虽然这不会超时,但它会阻止您将UI事件“泛滥”到主线程上,因为一次只能处理一个操作。
修改:在Yaur mentioned时,也可以通过Interlocked锁定此方法:
while (operation)
{
int pendingOperations = 0;
// ... Do work
// Update, but only if there isn't a pending update
if (0 == Interlocked.CompareExchange(ref pendingOperations, 1, 0))
{
control.BeginInvoke(new Action( () =>
{
// Update gauges
// Restore, so the next UI update can occur
Interlocked.Decrement(ref pendingOperations);
}));
}
}
// Update at the end (since you're last update might have been skipped)
control.Invoke(new Action(UpdateGuagesCompleted));
答案 1 :(得分:1)
对Control.Invoke
添加超时没有固有的支持。但是,您可以通过BeginInvoke
和超时检查来模拟这一点。
static void Invoke(this Control control, TimeSpan timeout, MethodInvoker callback)
{
if (!control.InvokeRequired) {
callback();
return;
}
using (ManualResetEvent mre = new ManualResetEvent(initialState: false)) {
bool cancelled = false;
MethodInvoker wrapped = () => {
mre.Set();
if (!cancelled) {
callback();
}
};
control.BeginInvoke(callback);
if (!mre.WaitOne(timeout)) {
cancelled = true;
}
}
}
此方法可以相当准确地模拟Control.Invoke
超时。
答案 2 :(得分:0)
如果您认为可能会在很短的时间内完成批次更新,其中每次更新都会覆盖其他更新,更好的解决方案更有可能只是创建一个经常触发的计时器,并根据您的工作人员确定应该执行的操作更新UI。创建一个实例字段,表示用于更新UI的数据,让工作人员在想要更新它时设置它,然后让计时器在每次滴答时使用存储的数据更新UI。如果工作人员碰巧在刻度事件之间将变量更改了10次,那么UI就更聪明了。
答案 3 :(得分:0)
如何仅将最新值存储到变量,然后处理Application.Idle事件?
我理解它的方式,当UI线程上的应用程序消息泵空闲时,会触发Application.Idle,从而确保UI准备好更新您的仪表