安排单火事件

时间:2010-07-13 14:15:18

标签: c# .net timer

我正在编写一个应用程序,需要在加载数据库时更新状态栏。我将标签设置为“Database loading ...”,然后使用BackgroundWorker加载数据库。当worker完成时,我将标签设置为“Database loaded”。但是,这仅在启动时完成,我不希望标签显示更长时间,并且希望在工作完成后几秒钟清除它。我可以在我的main上放置一个专用的计时器对象,但是这个单一动作将是它唯一的工作,而且似乎应该存在一个更优雅的解决方案。所以我尝试了lambdas:

void dataLoader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    DataLabel.Text = "Database Loaded";
    System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
    timer.Interval = 5000;
    timer.Tick += new EventHandler((o, a) =>
    {
        DataLabel.Text = "";
        (o as System.Windows.Forms.Timer).Enabled = false;
    });
}

当然timer的范围在函数退出后到期,并且永远不会调用Tick事件。

如何在不使用全局实例计时器的情况下运行简单的单火事件?

6 个答案:

答案 0 :(得分:2)

也许您可以在其正文中使用Thread.Sleep(N)的某些方法的异步调用。

答案 1 :(得分:2)

你的代码很好。事实上,在我看来,您的通用架构是最优雅的解决方案。你只是忘了启动计时器。您不必担心GC过早地收集计时器,因为它在启动时会自动“自动”生成。这当然会引发一个问题,即这是否会导致内存泄漏,因为每次都会创建一个新的计时器。我想不是因为定时器在停止时也会“自根”。所以以下应该可以正常工作。

void dataLoader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)  
{  
    DataLabel.Text = "Database Loaded";  
    var timer = new System.Windows.Forms.Timer();  
    timer.Interval = 5000;  
    timer.Tick += (o, a) =>  
    {  
        timer.Stop();
        DataLabel.Text = "";
    };
    timer.Start();
}  

答案 2 :(得分:1)

您可以创建一个类变量Timer,只需使用一次,然后使用null

此外,您可以使用ThreadPool注册一个方法 - 在此线程中,在触发对UI的调用以更新标签之前,睡眠所需的数量。

或者您可以重复使用后台工作程序以获得相同的效果。这样就可以节省您在UI线程上的Control.Invoke ...

答案 3 :(得分:0)

通常,即使在Visual Studio中,状态仍然存在,直到用户执行其他操作。这似乎是一种更好的方法,因为用户可能无法在5秒或10秒内检查状态。我认为最好在使用时更新状态(如点击菜单等)

答案 4 :(得分:0)

你可能只是让后台线程等待一段时间,例如:

void dataLoader_DoWork(object sender, DoWorkEventArgs e) {
    // Do work normally.

    // Report progress as complete.
    var worker = sender as BackgroundWorker;
    worker.ReportProgress(100);

    Thread.Sleep(5000);
}

void dataLoader_ProgressChanged(object sender, ProgressChangedEventArgs e) {
  if (e.ProgressPercentage == 100) {
    // Set label here
    DataLabel.Text = "Database Loaded";
  }
}

void dataLoader_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    DataLabel.Text = "";
}

这可能比触发异步方法好一点,因为已经为后台工作者创建了一个线程。这会更好吗?

答案 5 :(得分:0)

在ThreadPool中对WorkItem进行排队,睡眠5秒,然后BeginInvoke更新行为。这是一个基本的例子:

using System;
using System.Threading;
using System.Windows.Forms;

namespace CSharpScratch
{
    class Program
    {
        private static void Main()
        {
            var myForm = new MyForm();
            myForm.ShowDialog();
        }
    }

    class MyForm : Form
    {
        private readonly Label _label;

        public MyForm()
        {
            _label = new Label {Text = "Hello", Parent = this};
            Load += FormLoaded;
        }

        public void FormLoaded(object sender, EventArgs args)
        {
            ThreadPool.QueueUserWorkItem(x =>
                {
                    Thread.Sleep(5000);
                    BeginInvoke(new Action(() => _label.Text = "Goodbye"));
                });
        }
    }
}
相关问题