.net 如何停止Windows窗体按钮被单击两次

.net 如何停止Windows窗体按钮被单击两次,.net,winforms,button,.net,Winforms,Button,我在提交web请求的表单上有一个Windows窗体按钮。我希望能够在第一次单击按钮时禁用它,然后在收到响应时重新启用它。我对调用的代码和调用方式没有太多的控制权,因此我只能处理按钮事件,或者创建自己的按钮,从按钮继承如下: public class SingleClickButton : Button { protected override void OnClick(EventArgs e) { bool wasEnabled = this.Enabled;

我在提交web请求的表单上有一个Windows窗体按钮。我希望能够在第一次单击按钮时禁用它,然后在收到响应时重新启用它。我对调用的代码和调用方式没有太多的控制权,因此我只能处理按钮事件,或者创建自己的按钮,从按钮继承如下:

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

        if (wasEnabled)
        {
            base.OnClick(e);
        }
    }
}
我必须最后调用base OnClick方法,因为在web请求完成之前,按钮不会被禁用


我遇到的问题是,如果用户确实多次单击,则单击事件似乎会累积,并且仍在执行。是否有可能取消所有排队事件?还是有更简单的方法来解决我的问题?

我也有类似的问题。解决方法是在表单中添加一个计时器,然后使用该计时器重新启用我在click事件中禁用的按钮

    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秒钟(只是为了避免用户双击)

我也遇到了类似的问题。解决方法是在表单中添加一个计时器,然后使用该计时器重新启用我在click事件中禁用的按钮

    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秒(只是为了避免用户双击)

您需要使用以下场景:

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

        void CallBack()
        {
                this.Enabled = true;
        }
}
“RunAsynchronousMethod”可以创建新的“线程”或使用“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)();
                }
        }
}

您需要使用以下场景:

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

        void CallBack()
        {
                this.Enabled = true;
        }
}
“RunAsynchronousMethod”可以创建新的“线程”或使用“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)();
                }
        }
}

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

在处理完成之前是否可以禁用该按钮

首先,我实现了@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;
}

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

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;
}

启用和禁用按钮的问题是,如果单击事件中的内容运行得太快,以至于在双击操作的第二次单击之前按钮被启用(一些用户不理解,它只需要单击一次),那么下面是我的解决方案

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;
  }
}
private const int waittime=2;
private DateTime clickTime=DateTime.Now;
private void cmd_TimeStamp_Click(对象发送方,事件参数e)
{
如果((DateTime.Now-clickTime).Seconds
启用和禁用按钮的问题在于,如果单击事件中的内容运行得太快,以至于在双击操作的第二次单击之前按钮被启用(一些用户不理解,它只需要单击一次),那么下面是我的解决方案

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;
  }
}
private const int waittime=2;
private DateTime clickTime=DateTime.Now;
private void cmd_TimeStamp_Click(对象发送方,事件参数e)
{
如果((DateTime.Now-clickTime).Seconds
请确认,回调是所有工作发生的方法?如果在其内部调用this.Enabled将导致跨线程错误。否,在工作完成后调用回调函数。查看我的编辑,了解详细信息。您应该使用调用程序重新启用按钮必须确认,回调是所有工作发生的方法?如果在其内部调用this.Enabled将导致跨线程错误。否,在工作完成后调用回调函数。查看我的编辑,了解详细信息。您应该使用调用程序重新启用按钮,以及当操作耗时超过4秒时会发生什么:)?当操作耗时超过4秒时会发生什么:)?