【问题标题】:Calling Timer Tick event after enabling timer in another class在另一个类中启用计时器后调用 Timer Tick 事件
【发布时间】:2012-02-05 01:25:27
【问题描述】:

我一定是做错了什么,但我想不通。我有一个表格,我在 VS 中添加了一个计时器控件。我还有一个类正在监视应用程序的启动(notepad.exe)。当事件到达时,它应该启用计时器,设置间隔并在每个滴答声上做一些事情(比如触发消息框或更改标签)。这似乎没有发生。看看代码可以帮助有人给我一个线索。代码如下:

public partial class Monitor : Form
{
    EventWatcher eventWatch = new EventWatcher();
    ManagementEventWatcher startWatcher = new ManagementEventWatcher();
    ManagementEventWatcher endWatcher = new ManagementEventWatcher();


    public Monitor()
    {
        InitializeComponent();
        startWatcher  = eventWatch.WatchForProcessStart("notepad.exe");
        endWatcher =   eventWatch.WatchForProcessEnd("notepad.exe");
    }

    private void appTimer_Tick(object sender, EventArgs e)
    {
        label1.Text = "tick";
        MessageBox.Show("Tick");
    }

}

而观察者类是

class EventWatcher
{

    public ManagementEventWatcher WatchForProcessStart(string processName)
    {
        string queryString =
            "SELECT TargetInstance" +
            "  FROM __InstanceCreationEvent " +
            "WITHIN  2 " +
            " WHERE TargetInstance ISA 'Win32_Process' " +
            "   AND TargetInstance.Name = '" + processName + "'";

        // The dot in the scope means use the current machine
        string scope = @"\\.\root\CIMV2";

        // Create a watcher and listen for events
        ManagementEventWatcher watcher = new ManagementEventWatcher(scope, queryString);
        watcher.EventArrived += ProcessStarted;
        watcher.Start();
        return watcher;
    }


    public void ProcessStarted(object sender, EventArrivedEventArgs e)
    {
       Monitor monitor = new Monitor();
       //set timer interval and start time for Monitor class. (form)
       monitor.appTimer.Interval = 5000;
       monitor.appTimer.Enabled = true;

       MessageBox.Show("notepad started");


    }
}

我注意到两件事:

当 notepad.exe 启动并且我将 MessageBox.Show("notpad started"); 行注释掉时,计时器滴答事件中的消息框不会触发。如果如上所示,它将显示两个消息框(记事本已启动和勾选)。但是,label1.Text 无论如何都不会改变。

我不确定我做错了什么。我确信这与如何处理计时器事件有关,但我不确定我应该做什么。有什么想法吗?

【问题讨论】:

    标签: c# timer


    【解决方案1】:

    您的代码创建了一个新的 Monitor 实例。 因此,您没有访问调用 eventWatch.WaitForProcessStart() 的 Monitor 实例的属性,因此它们不会更改。 解决此问题的一种方法是在 ProcessStarted() 被触发后立即触发一个事件。 您的代码可能如下所示:

    class EventWatcher
    {
    
        public event EventHandler<EventArrivedEventArgs> ProcessStarted;
    
        public ManagementEventWatcher WatchForProcessStart(string processName)
        {
            string queryString =
                "SELECT TargetInstance" +
                "  FROM __InstanceCreationEvent " +
                "WITHIN  2 " +
                " WHERE TargetInstance ISA 'Win32_Process' " +
                "   AND TargetInstance.Name = '" + processName + "'";
    
            // The dot in the scope means use the current machine
            string scope = @"\\.\root\CIMV2";
    
            // Create a watcher and listen for events
            ManagementEventWatcher watcher = new ManagementEventWatcher(scope, queryString);
            watcher.EventArrived += OnProcessStarted;
            watcher.Start();
            return watcher;
        }
    
    
        protected virtual void OnProcessStarted(object sender, EventArrivedEventArgs e)
        {
    
            EventHandler<EventArrivedEventArgs> copy = ProcessStarted;
            if (copy != null)
                copy(sender, e); // fire the event
    
        }
    }
    
    public partial class Monitor : Form
    {
        EventWatcher eventWatch = new EventWatcher();
        ManagementEventWatcher startWatcher = new ManagementEventWatcher();
        ManagementEventWatcher endWatcher = new ManagementEventWatcher();
    
    
        public Monitor()
        {
            InitializeComponent();
            startWatcher  = eventWatch.WatchForProcessStart("notepad.exe");
            startWatcher.ProcessStarted += startWatcher_ProcessStarted; // subscribe to the event
            endWatcher =   eventWatch.WatchForProcessEnd("notepad.exe");
        }
    
        private void startWatcher_ProcessStarted(object sender, EventArrivedEventArgs e)
        { 
            Monitor monitor = new Monitor();
            //set timer interval and start time for Monitor class. (form)
            monitor.appTimer.Interval = 5000;
            monitor.appTimer.Enabled = true;
    
            MessageBox.Show("notepad started");
        }
    
        private void appTimer_Tick(object sender, EventArgs e)
        {
            label1.Text = "tick";
            MessageBox.Show("Tick");
        }
    
    }
    

    【讨论】:

    • 感谢您的帮助,但它似乎没有任何不同。如果显示“记事本已启动”的消息框不存在,则其他消息框不会在代码中触发。标签不会改变任何一种方式,我现在得到跨线程错误。我怀疑你对新实例说了什么。将计时器设置为静态字段不会解决此问题吗?但事实并非如此。
    【解决方案2】:

    看起来label1.Text 不会因为您从不同的线程运行而改变。您需要在该标签上运行调用以从 ManagementEventWatcher 更新它。

    使用这个类:

    using System;
    using System.Windows.Forms;
    
    public static class ControlExtensions
    {
        /// <summary> 
        /// Executes the Action asynchronously on the UI thread, does not block execution on the calling thread. 
        /// </summary> 
        /// <param name="control"></param> 
        /// <param name="code"></param> 
        public static void UIThread(this Control @this, Action code)
        {
            if (@this.InvokeRequired)
            {
                @this.BeginInvoke(code);
            }
            else
            {
                code.Invoke();
            }
        }
    }
    
    and replace `label1.Text = "tick" ` with
    
    this.UIThread(() => this.label1.Text = "tick"));
    

    【讨论】:

    • 这似乎工作得更好,因为现在 label1 随我的旧代码发生了变化。但是,只有当我在 ProcessStarted 函数中有一个消息框时才会发生这种情况。
    猜你喜欢
    • 2015-12-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-13
    相关资源
    最近更新 更多