1

我有以下代码。在同一个代码块中,我禁用一个控件然后启用它,但它似乎不起作用并保持初始 IsEnable 状态。

// Button never enable
public void Foo()
{
   button1.IsEnabled = false
   Thread.Sleep(3000);
   button1.IsEnabled = true;
   Thread.Sleep(3000);
   button1.IsEnabled = false;
}
4

4 回答 4

4

首先: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被调用时,按钮被禁用(IsEnabledis false)。然后,等待 3 秒后,将按钮设置为启用,然后再次禁用它。按钮实际上处于那种状态,但是没有视觉反馈(如:如果你看表​​单,你不会看到按钮“闪烁”)。

这是因为您通过调用Thread.Sleep. 这可以防止窗口接收窗口消息,这些消息告诉窗口何时重新绘制自身或其子之一(按钮不“知道”它应该是灰色的)。

因此,您需要让窗口有机会接收消息并更新其子级。在 Windows 窗体应用程序中,这是通过Application.DoEvents处理所有待处理的窗口消息来完成的。

WPF 中没有这样的东西Application.DoEvents,但是我发布的代码通过生成一个Thread什么都不做的代码来模拟这一点 - 但是在更改按钮的启用状态和阻塞 UI 线程之间的一小段时间足以让按钮控件重新绘制自身。

于 2012-04-03T08:49:21.687 回答
1

当您调用 sleep 时,当前线程被挂起并且 UI 将冻结(当您尝试单击 UI 时,它会变灰)直到线程被唤醒。因此线程休眠了 6 秒,您不会注意到按钮已启用。最后,该按钮保持禁用状态。

您应该使用调度程序在另一个线程中运行您的代码。

于 2012-04-03T08:48:41.937 回答
0

有没有想过你可能在 UI-Thread 上?阅读wpf 中的调度程序

于 2012-04-03T08:47:17.663 回答
0

正如其他人所说,UI 线程正在处理队列中的事件。如果您的函数在 UI 线程上被调用,则在完成当前更新之前,它无法处理 UI 更新。

NET 确实提供了许多线程选项,例如 BackgroundWorker、Thread、ThreadPool 等。

较新的 NET 框架还提供了允许 GUI 线程在事件期间执行其他工作的 async/await 方法。

于 2013-10-18T14:54:42.380 回答