代码之家  ›  专栏  ›  技术社区  ›  dlras2

安排单个火灾事件

  •  3
  • dlras2  · 技术社区  · 14 年前

    我正在编写一个应用程序,在加载数据库时需要更新状态栏。我将标签设置为“数据库加载…”,然后用 BackgroundWorker . 当工作进程完成时,我将标签设置为“数据库加载”。但是,这只在启动时完成,我不希望标签在很长时间内可见,并且希望在工作进程完成后几秒钟将其清除。我可以将一个专用的计时器对象放在我的主对象上,但是这个单独的操作将是它唯一的工作,而且看起来应该存在一个更优雅的解决方案。所以我尝试了兰巴斯:

    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 回复  |  直到 14 年前
        1
  •  2
  •   Brian Gideon    14 年前

    您的代码基本上是正确的。事实上,在我看来,您的总体架构是最优雅的解决方案。你忘了启动计时器。您不必担心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
  •  2
  •   Stremlenye    14 年前

    也许您可以使用一些方法的异步调用,在它的主体中使用thread.sleep(n)。

        3
  •  1
  •   Adam Houldsworth    14 年前

    可以创建类变量 Timer ,使用一次,然后 null 它。

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

    或者你可以为同样的效果重新使用后台工作人员。这就省去了你需要 Control.Invoke 到UI线程上…

        4
  •  0
  •   ata    14 年前

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

        5
  •  0
  •   Matthew Abbott    14 年前

    您可以让后台线程等待更长时间,例如:

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

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

        6
  •  0
  •   statenjason    14 年前

    将工作项在线程池中排队,休眠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"));
                    });
            }
        }
    }