我有以下代码。在同一个代码块中,我禁用一个控件然后启用它,但它似乎不起作用并保持初始 IsEnable 状态。
// Button never enable
public void Foo()
{
button1.IsEnabled = false
Thread.Sleep(3000);
button1.IsEnabled = true;
Thread.Sleep(3000);
button1.IsEnabled = false;
}
首先:Foo
方法完成后按钮未启用并不奇怪,因为最后一行禁用了按钮。
如果你想“看到”按钮的启用状态变化,你需要在休眠前处理窗口消息。Thread.Sleep
导致 UI 线程休眠,因此不会对用户界面进行更新。您需要做的是让应用程序处理所有待处理的窗口消息。
public static void DoEvents()
{
if (Application.Current != null)
Application.Current.Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate { }));
}
public void Foo()
{
button1.IsEnabled = false
DoEvents();
Thread.Sleep(3000);
button1.IsEnabled = true;
DoEvents();
Thread.Sleep(3000);
button1.IsEnabled = false;
}
编辑
进一步解释:
当第一个Thread.Sleep
被调用时,按钮被禁用(IsEnabled
is false
)。然后,等待 3 秒后,将按钮设置为启用,然后再次禁用它。按钮实际上处于那种状态,但是没有视觉反馈(如:如果你看表单,你不会看到按钮“闪烁”)。
这是因为您通过调用Thread.Sleep
. 这可以防止窗口接收窗口消息,这些消息告诉窗口何时重新绘制自身或其子之一(按钮不“知道”它应该是灰色的)。
因此,您需要让窗口有机会接收消息并更新其子级。在 Windows 窗体应用程序中,这是通过Application.DoEvents
处理所有待处理的窗口消息来完成的。
WPF 中没有这样的东西Application.DoEvents
,但是我发布的代码通过生成一个Thread
什么都不做的代码来模拟这一点 - 但是在更改按钮的启用状态和阻塞 UI 线程之间的一小段时间足以让按钮控件重新绘制自身。
当您调用 sleep 时,当前线程被挂起并且 UI 将冻结(当您尝试单击 UI 时,它会变灰)直到线程被唤醒。因此线程休眠了 6 秒,您不会注意到按钮已启用。最后,该按钮保持禁用状态。
您应该使用调度程序在另一个线程中运行您的代码。
有没有想过你可能在 UI-Thread 上?阅读wpf 中的调度程序。
正如其他人所说,UI 线程正在处理队列中的事件。如果您的函数在 UI 线程上被调用,则在完成当前更新之前,它无法处理 UI 更新。
NET 确实提供了许多线程选项,例如 BackgroundWorker、Thread、ThreadPool 等。
较新的 NET 框架还提供了允许 GUI 线程在事件期间执行其他工作的 async/await 方法。