【问题标题】:How to implement a delay after a button can be pressed again [duplicate]如何在可以再次按下按钮后实现延迟[重复]
【发布时间】:2015-07-27 23:14:34
【问题描述】:

我有一个 c# winforms 应用程序,我正在使用它来调用 ASP.net webservice 方法来执行一些数据库操作。

...
namespace WebServiceClient
{
    public partial class Form1 : Form
    {
        Service1ref.Service1 wbsrv = new Service1ref.Service1();
        bool lbl_hid = true;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void button1_Click(object sender, EventArgs e)
        {
            label3.ForeColor = System.Drawing.Color.Azure;
            label3.Text = "Request sent...";
            wbsrv.Url = textBox1.Text;
            string response = wbsrv.GenerateRandomSensorData(textBox2.Text);

            label3.Text = response;
            if (label3.Text.Contains('7'))
                label3.ForeColor = System.Drawing.Color.Green;
            else
                label3.Text = "Error";
                label3.ForeColor = System.Drawing.Color.Red;
            if (lbl_hid == true)
            {
                label3.Show();
                lbl_hid = false;
            }
        }
...

大多数时候整个过程太快了,"Request sent.." 部分甚至没有显示出来。我想在那里放一个小延迟,这样如果响应速度快于 1 秒,它应该等待整整一秒,然后再继续执行代码。此外,发送按钮应在每次点击后停用 3 秒。我需要计时器吗?我试图完成一些事情,但对我来说太难了。

【问题讨论】:

  • 这看起来像 Winform,。不是 ASP.Net
  • 是的 asp.net 是被消费的网络服务,我放标签的错误

标签: c# winforms


【解决方案1】:

async 标记button1 处理程序,然后像这样使用await Task.Delay()

    private async void button1_Click(object sender, EventArgs e)
    {
        button1.Enabled = false;

        label3.ForeColor = System.Drawing.Color.Azure;
        label3.Text = "Request sent...";
        wbsrv.Url = textBox1.Text;
        string response = wbsrv.GenerateRandomSensorData(textBox2.Text);
        await Task.Delay(1000);

        label3.Text = response;
        if (label3.Text.Contains('7'))
        { 
            label3.ForeColor = System.Drawing.Color.Green;
        }
        else
        {
            label3.Text = "Error";
            label3.ForeColor = System.Drawing.Color.Red;
        }

        if (lbl_hid == true)
        {
            label3.Show();
            lbl_hid = false;
        }

        await Task.Delay(2000);
        button1.Enabled = true;
    }

请注意,无论请求实际花费了多长时间,这都会额外等待一秒...并在此之后强制再等待两秒,然后再重新启用按钮。

【讨论】:

    【解决方案2】:

    您可以使用 3,000 毫秒的计时器。单击按钮时,您将禁用该按钮并启动计时器。计时器有一个名为 TimeElapsed 的事件,您需要订阅该事件,因为您需要再次激活该按钮。

    【讨论】:

    • 所以,UI 挂了 3000 毫秒,你需要使用另一个线程。
    • 您不应该在主线程(UI 线程)中运行长时间的进程。 UI 应始终具有响应性,以便用户知道发生了什么,并为他提供取消流程的方法。
    【解决方案3】:

    您可能想要更聪明一点,并从 3 秒的等待中扣除调用 Web 服务所花费的时间。所以不是 WS Call + 3 秒。

    private async void button1_Click(object sender, EventArgs e)
    {
        //Record the time when button was clicked
        DateTime timeButtonWasClicked = DateTime.Now;
    
        button1.Enabled = false;
        label3.ForeColor = System.Drawing.Color.Azure;
        label3.Text = "Request sent...";
    
        //Force the label to be repainted
        label3.Invalidate();
    
        wbsrv.Url = textBox1.Text;
        string response = wbsrv.GenerateRandomSensorData(textBox2.Text);
    
        //If the user has waited less than 3 seconds, 
        //make them wait the difference, otherwise 
        //dont force users to wait at least 6 or so seconds
        TimeSpan ts = DateTime.Now - timeButtonWasClicked;
        if (ts.Seconds < 3) await Task.Delay(TimeSpan.FromSeconds(3).Subtract(ts));
    
        label3.Text = response;
        if (label3.Text.Contains('7')) { 
            label3.ForeColor = System.Drawing.Color.Green;
        }
        else {
            label3.Text = "Error";
            label3.ForeColor = System.Drawing.Color.Red;
        }
    
        if (lbl_hid) {  //Dont bother testing Booleans for "== true"
            label3.Show();
            lbl_hid = false;
        }
        button1.Enabled = true;
    }
    

    编辑:

    请注意,我不认可这种方法,它非常老套,如果你不阅读使用业务逻辑层和 C# 控件绑定,它会导致非常糟糕的编程实践。我提供这个编辑以帮助您继续前进并了解更多信息。 我是在没有 IDE 的情况下编写的,所以可能存在错误。

    //Declare a timer control
    private static System.Timers.Timer aTimer;
    
    //We need to check when the response is populated between two methods, so I've declared it as a private member variable
    private string response = string.Empty;
    
    private void button1_Click(object sender, EventArgs e)
    {
        button1.Enabled = false;
        label3.ForeColor = System.Drawing.Color.Azure;
        label3.Text = "Request sent...";
    
        //Force the label to be repainted
        label3.Invalidate();
    
        //Instantiate the timer and set a one second interval.
        aTimer = new System.Timers.Timer();
        aTimer.Interval = 1000;
    
        // Hook up the Elapsed event for the timer. 
        aTimer.Elapsed += OnTimedEvent;
    
        // Start the timer
        aTimer.Enabled = true;
    
        wbsrv.Url = textBox1.Text;
        response = wbsrv.GenerateRandomSensorData(textBox2.Text);
    
    }
    
    private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
    {
        //Check the response string variable is NOT empty
        if  (!string.IsNullOrEmpty(response)) 
        {
           label3.Text = response;
           // Stop the timer
           aTimer.Enabled = false;
        }
        else
        {
           return;
        }
    
        if (label3.Text.Contains('7')) { 
            label3.ForeColor = System.Drawing.Color.Green;
        }
        else {
            label3.Text = "Error";
            label3.ForeColor = System.Drawing.Color.Red;
        }
    
        if (lbl_hid) { 
            label3.Show();
            lbl_hid = false;
        }
        button1.Enabled = true;
    }
    

    【讨论】:

    • 如果您使用的是 VS2010,它将无法正常工作。对于 VS2012,您可以使用 NuGet 并安装 Microsoft.Bcl.Async。它在VS2013中没有问题。为什么你有哪个 Visual Studio 版本?
    • 我目前为这个项目在 vs2008 上开发,所以是的,.net 4.0 是我可以去的最高版本。如果您可以将上述内容转换为使用 Timer 控件,那就太棒了!
    • 查看我的编辑,请阅读更多内容,以便您了解这不是好的编码。当然它会起作用,但它不是纯粹的、可重用的、封装的、多态的或抽象的。它的粗糙和肮脏!祝你好运! ps 可能有一两个错误...
    【解决方案4】:

    await Task.Delay() 是最好的解决方案。如上。 当我没有异步等待时,我尝试了另一种方法,由于某些原因无法更新 .net 框架和 Visual Studio。

       private void button1_Click(object sender, EventArgs e)
        {
            button1.Enabled = false;
    
            label3.ForeColor = System.Drawing.Color.Azure;
            label3.Text = "Request sent...";
            wbsrv.Url = textBox1.Text;
            string response = wbsrv.GenerateRandomSensorData(textBox2.Text);
            // Custom Task Class 
            Task.Delay(TimeSpan.FromSeconds(1)).ContinueWith(AfteDelay); 
    
        }
    
       private void AfterDelay(){
    
                label3.Text = response;
                if (label3.Text.Contains('7'))
                { 
                    label3.ForeColor = System.Drawing.Color.Green;
                }
                else
                {
                    label3.Text = "Error";
                    label3.ForeColor = System.Drawing.Color.Red;
                }
    
                if (lbl_hid == true)
                {
                    label3.Show();
                    lbl_hid = false;
                }
    
                button1.Enabled = true;
       }
    

    自定义任务类将如下所示。

       using System.Windows.Forms.Timer;
    
      public class Task
    {
        Timer timer;
        public static Task Delay(TimeSpan timeSpan)
        {
            Task task = new Task();
            task.timer = new Timer();
            task.timer.Interval = Convert.ToInt32(timeSpan.TotalMilliseconds);
            return task;
    
        }
        private Task()
        {
    
        }
        public static Task Delay(int miliSeconds)
        {
            Task task = new Task();
            task.timer = new Timer();
            task.timer.Interval = miliSeconds;
            return task;
    
        }
        public static void Run(Action action)
        {
            Timer timer = new Timer();
            timer.Interval = 1;
            timer.Enabled = true;
            timer.Tick += delegate
            {
                timer.Stop();
                timer = null;
                action();
            };
        }
        EventHandler elapsed;
        public void ContinueWith(Action action)
        {
    
            timer.Enabled = true;
            elapsed = delegate
            {
                Stop();
                action();
            };
            //bind the event
            timer.Tick += elapsed;
    
    
        }
        private void handleEvent(Action action)
        {
    
        }
        public void Stop()
        {
            timer.Stop();
            timer.Enabled = false;
            //unbind the event
            if (elapsed != null)
            {
                timer.Tick -= elapsed;
            }
        }
    
    }
    

    【讨论】:

    • 在我的回答中查看 cmets。恐怕她正在使用 VS2008 .Net 4,所以没有等待善良:(
    • @JeremyThompson 它适用于 2008 年,甚至适用于 .net 3.5,因为我自己破坏了任务类。
    猜你喜欢
    • 1970-01-01
    • 2021-11-16
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多