【问题标题】:Cannot enable a disabled a control in the same block无法在同一块中启用禁用的控件
【发布时间】:2012-04-16 21:47:12
【问题描述】:

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

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

【问题讨论】:

    标签: c# wpf button isenabled


    【解决方案1】:

    有没有想过你可能在 UI 线程上?阅读about the dispatcher in wpf

    【讨论】:

      【解决方案2】:

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

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

      【讨论】:

        【解决方案3】:

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

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

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

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

        【讨论】:

        • +1 有效。但解释不清楚。在第一个 Thread.Sleep 结束后,应在第二个 Thread.Sleep 之前启用按钮。我仍然应该注意到按钮状态的变化。没有?
        • 谢谢,但是嗯...一旦第一个 Thread.Sleep 结束,UI 应该被解除阻塞,以便在第二个 Thread.Sleep 再次阻塞 UI 之前获得视觉反馈。所以我仍然看不到按钮是如何不闪烁的。
        • 这是因为 UI 仅在 UI 线程空闲时更新(您的应用程序“没有做任何事情”)。在Thread.Sleep 和下一个button1.IsEnabled 之后,线程不是空闲的——两行之间没有“中断”(您的应用程序“正在做某事”——它启用/禁用按钮)。要在方法执行期间使 UI 线程进入空闲状态而不阻塞它,您可以在 Windows 窗体中使用 Application.DoEvents 或我在上面在 WPF 中发布的代码。
        【解决方案4】:

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

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

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多