为什么禁用的按钮还能被点击?

3

这个案例是使用 C# WPF。我想要在点击按钮后立即禁用它,以防止短时间内重复点击。我已经在 OnClick_Event 中禁用了该按钮,但仍然可以被点击。

以下是部分源代码:

private void Button_Click_UpdateBurndownChart(object sender, RoutedEventArgs e)
{
   if(threadNotWorking)
   {
      updateButton.IsEnabled = false;
      startWorkThread();
   }
}

private void startWorkThread()
{
     ... ...
    //after finish required process
    updateButton.IsEnabled = true;
}

有没有办法完成这个任务?

如果你注释掉startWorkThread会发生什么?我怀疑它会执行一个循环,停止处理Windows消息。如果是这种情况,你应该使用后台工作线程(或在循环中插入Application.DoEvents作为一个糟糕但容易的解决方案)。 - PeterJ
你可以将按钮的“IsEnabled”属性绑定到“threadNotWorking”。 - sa_ddam213
鼠标点击被添加到消息队列中,并一直停留在那里,直到startWorkThread()返回并且您的代码重新进入调度程序循环。此时按钮不再被禁用。 - Hans Passant
3个回答

3

你可能需要使用调度程序,这里可能存在线程问题(回调函数在单独的线程上运行,尝试访问在另一个线程上运行的UI)。请尝试以下方法...

updateButton.Dispatcher.BeginInvoke(
    new ThreadStart(() => updateButton.IsEnabled = false), 
    System.Windows.Threading.DispatcherPriority.Input, null);

替代

updateButton.IsEnabled = false;

谢谢。它不起作用。即使在按钮被禁用后,在事件处理程序内启动新线程,禁用的按钮仍然会接受点击事件。我使用Snoop检查事件,并发现单击事件发生在工作线程完成后。但我的假设是,在工作线程执行期间应禁用按钮,不应发生任何单击事件。我猜测有些地方出了问题,但不知道具体是哪里。 - user1908842
我想我明白了。也许你应该在线程内再添加一行代码来先禁用按钮(可能需要使用Dispatcher),然后执行操作完成后再重新启用按钮(就像你现在的代码一样):private void startWorkThread() { updateButton.IsEnabled = false; //执行所需的操作 updateButton.IsEnabled = true; } - rbtLong
你可能需要使用调度程序来处理这两行代码。 - rbtLong
谢谢。问题在于工作线程启动了第二个线程来更新UI项。我将处理UI项的操作从第二个线程移动到了工作线程中,问题得到了解决。 - user1908842

0

如果您改变事件的顺序,会发生什么:

  updateButton.IsEnabled = false;
  startWorkThread();

  startWorkThread();
  updateButton.IsEnabled = false;

请告诉我这个进展如何。


0
看起来你是在启动线程后立即启用了按钮,而没有等待线程完成。最好使用BackgroundWorker,并在RunWorkerCompleted事件中启用你的按钮。虽然你也可以通过在Process结束时使用BeginInvoke来启用按钮,实现类似的效果。
public void doWork()
{
    System.Threading.Thread.Sleep(10000); //Simulating your Process
    Dispatcher.BeginInvoke(new System.Threading.ThreadStart(delegate() { updateButton.IsEnabled = true; }), System.Windows.Threading.DispatcherPriority.Background);
}

使用BackgroundWorker的示例

using System.ComponentModel;

public partial class MainWindow : Window
{
    BackgroundWorker bgw;
    public MainWindow()
    {
        InitializeComponent();
        bgw = new BackgroundWorker();
        bgw.DoWork += new DoWorkEventHandler(bgw_DoWork);
        bgw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bgw_RunWorkerCompleted);

    }

    void bgw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        updateButton.IsEnabled = true;
    }

    void bgw_DoWork(object sender, DoWorkEventArgs e)
    {
        System.Threading.Thread.Sleep(10000); //Simulating your work
    }



    private void startWorkThread()
    {
        bgw.RunWorkerAsync();
    }

    private void updateButton_Click(object sender, RoutedEventArgs e)
    {
        if (bgw.IsBusy != true)
        {
            updateButton.IsEnabled = false;
            startWorkThread();
        }
    }
}

这个也不起作用。按钮看起来被禁用了,但仍然可以接受点击和稍后处理的事件。 - user1908842
@user1908842 我只能说它在我的系统上运行正常。按钮被禁用,不会响应点击。我认为你需要发布你的startWorkThread方法的代码。另外,你是说BackgroundWorker也不起作用,还是只有第一个方法不起作用? - Mark Hall
1
问题在于工作线程启动了另一个线程来刷新用户视图。 - user1908842
@user1908842,很高兴你找到了它。 - Mark Hall
1
问题在于工作线程启动了另一个线程来更新用户视图。 private void BackgroundWorker1_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e) { System.Threading.ThreadPool.QueueUserWorkItem delegate { ... (System.Action)delegate() { startChartRevProcess(); ... } StartChartRevProcess必须处理一些UI项,并像上面那样作为另一个线程启动。 后来,我将UI处理移动到了工作线程中,并同步启动了startChartRevProcess,问题得到解决。 谢谢大家。 - user1908842
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接