【问题标题】:How to stop a Windows Forms Button being clicked twice如何停止两次单击 Windows 窗体按钮
【发布时间】:2009-06-09 14:54:25
【问题描述】:

我在提交 Web 请求的表单上有一个 Windows 表单按钮。我希望能够在第一次单击按钮时禁用它,然后在收到响应时重新启用它。我对被调用的代码及其调用方式没有太多控制权,所以我只能玩 Button 事件,或者我可以创建自己的从 Button 继承的按钮,如下所示:

public class SingleClickButton : Button
{
    protected override void OnClick(EventArgs e)
    {
        bool wasEnabled = this.Enabled;
        this.Enabled = false;

        if (wasEnabled)
        {
            base.OnClick(e);
        }
    }
}

我必须最后调用基本 OnClick 方法,因为在 Web 请求完成之前按钮不会禁用。

我遇到的问题是,如果用户确实单击了多次,则单击事件似乎已经建立并且仍然被执行。有没有办法取消所有排队的事件?或者我的问题有更简单的解决方案吗?

【问题讨论】:

    标签: .net winforms button


    【解决方案1】:

    你需要使用这个场景:

    public class SingleClickButton : Button
    {
            protected override void OnClick(EventArgs e)
            {
                    this.Enabled = false;
                    RunAsynchronousMethod( CallBack );
                    base.OnClick(e);
            }
    
            void CallBack()
            {
                    this.Enabled = true;
            }
    }
    

    “RunAsynchronousMethod”可以创建新的“Thread”或者使用“ThreadPool.QueueUserWorkItem)”。

    编辑:

    public class SingleClickButton : Button {
            protected override void OnClick(EventArgs e) {
                    this.Enabled = false;
                    RunAsynchronousMethod( CallBack );
                    base.OnClick(e);
            }
    
            void CallBack() {
                    this.Enabled = true;
            }
    
            void RunAsynchronousMethod( Action callBack ) {
                    // there you can use ThreadPool or Thread
                    ThreadPool.QueueUserWorkItem( this.Worker, callBack );
            }
    
            void Worker( object callBack ) {
                    try {
                        // some operations
                    }
                    finally {
                        // after operations was proceeded, the callback function will
                        // be called
                        ((Action)callBack)();
                    }
            }
    }
    

    【讨论】:

    • 只是确认一下,回调是所有工作发生的方法吗?如果在里面调用 this.Enabled 会导致跨线程错误。
    • 不,回调函数在工作完成后被调用。查看我的编辑,了解详细信息。
    • 您应该使用调用程序重新启用按钮
    【解决方案2】:

    我遇到了类似的问题。通过在表单中​​添加一个计时器来解决它,然后使用该计时器重新启用我在点击事件中禁用的按钮。

        private void btnPrintReport_Click(object sender, EventArgs e)
        {
            btnPrintReport.Enabled = false;
            timerEnablePrint.Enabled = true;
            BackgroundProcess.Add("Printing", new WaitCallback(generateReport), null);
        }
    
    
        private void timerEnablePrint_Tick(object sender, EventArgs e)
        {
            btnPrintReport.Enabled = true;
            timerEnablePrint.Enabled = false;
        }
    

    将计时器设置为合理的间隔。我用4秒(只是为了避免用户双击)

    【讨论】:

    • 当操作超过 4 秒时会发生什么:)?
    【解决方案3】:

    也许在处理完成之前禁用按钮?

    【讨论】:

      【解决方案4】:

      首先我实现了@TcKs 答案,这对我有很大帮助,但“灰色按钮”给我带来了一些问题。 (部分用户认为系统有问题) 所以我做了一个小改动,只忽略后续的点击。

      bool ignoreClick = false;
      protected override void OnClick(EventArgs e)
      {
              // Prevent DoubleClick
              if (ignoreClick) return;
              ignoreClick = true;
              ThreadPool.QueueUserWorkItem(this.Worker);
              base.OnClick(e);
      }
      void Worker(object obj)
      {
              try
              {
                  Thread.Sleep(300);                
               }
               catch { }
               ignoreClick = false;
      }
      

      【讨论】:

        【解决方案5】:

        启用和禁用按钮的问题在于,如果您在 click 事件中运行得如此之快,以至于在双击操作的第二次单击之前启用了按钮(有些用户不明白它只需要 1点击)所以这是我的解决方案。

        private const int waittime = 2;
        private DateTime clickTime = DateTime.Now;
        
        private void cmd_TimeStamp_Click(object sender, EventArgs e)
        {
          if ((DateTime.Now - clickTime).Seconds < waittime)
            return;
          else
            clickTime = DateTime.Now;
          try
          {
            cmd_TimeStamp.Enabled = false;
            //Do some stuff in here
          }
          catch (Exception ex)
          {
            //Show error if any
            MessageBox.Show(this, ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
          }
          finally
          {
            cmd_TimeStamp.Enabled = true;
          }
        }
        

        【讨论】:

          猜你喜欢
          • 2018-08-15
          • 2011-06-11
          • 1970-01-01
          • 2011-09-02
          • 2017-07-13
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2010-11-10
          相关资源
          最近更新 更多