我有这样的事情:
void ClickHandler() // Called from several places
{ // Try to prevent queuing accidental extra clicks during lengthy operation
GetMainWindow().IsEnabled = false; // "GetMainWindow()" you know what I mean
DoLengthyStuffInThisThread(); // Yes, I know I shouldnt
PresentResult();
GetMainWindow().IsEnabled = true;
}
基本上就是这样。尽管如此:
即使我设置了IsEnabled = false,它也没有达到预期效果,但在操作过程中我会额外点击。 (如果我在没有恢复值的情况下返回它会产生影响。)我假设通常我的线程需要返回才能使禁用生效但我宁愿不创建额外的线程。
答案 0 :(得分:2)
你必须将冗长的工作卸载到另一个线程。在封闭方法完成之后,UI不会通知此更改(因此,没有机会通过布局传递刷新它的状态)。
我会想象在漫长的方法中发生的任何事情都是操纵UI上显示的一些数据。如果您正在使用数据绑定,此操作将在后台填充UI(如果它在后台线程上运行),然后当该操作完成时,它可以告诉UI重新启用它自己。
这是半伪代码,但请查看Task.Factory.StartNew和Dispatcher.BeginInvoke。
public void ClickHandler()
{
MainWindow.IsEnabled = false;
Task.Factory.StartNew(() =>
{
// Length work goes here
}).ContinueWith((result) =>
{
Dispatcher.BeginInvoke(() =>
{
MainWindow.IsEnabled = true;
});
});
}
答案 1 :(得分:0)
谢谢大家的回答。最好的答案实际上是Will Eddins的 * 评论中的一个。特别感谢! *
我对uggly问题的回答是:System.Windows.Forms.Application.DoEvents();
不是很好看,但这是我必须要做的。孩子们,不要在家里试试这个!
public void WrapLengthyWork(Action lengthyWork)
{
SetWaiting(true);
System.Windows.Forms.Application.DoEvents();
lengthy();
SetWaiting(false);
}
public void SetWaiting(bool wait)
{
if (wait == true)
{
Mouse.OverrideCursor = Cursors.Wait;
Application.Current.MainWindow.IsEnabled = false;
}
else
{
IsEnabled = true;
Mouse.OverrideCursor = Cursors.Arrow;
}
}
此外,对于所有建议我正确使用线程切换的人:也感谢你。我(正如我所提到的)痛苦地意识到上述片段很差编码风格。我的问题是“LengthyWork()
”本身 riddled 带有引用回GUI的东西,必须在GUI线程中运行,例如:
while(stuffToDo)
{
Fetch();
Calculate();
UpdateGUI();
}
考虑到施加的时间限制(几小时)和有限的任务(“防止处理期间的点击并显示等待光标并触摸其他任何东西”),遗憾的是,正确的解决方案不是一种选择。
答案 2 :(得分:-1)
@ william-custode是对的,你应该完成主应用程序线程的繁重工作。但是,在开始“DoLengthyStuffInThisThread”之前,解决方法是forcing the window's message loop to consume all currently dispatched messages。