简体   繁体   English

在另一个类中启用计时器后调用Timer Tick事件

[英]Calling Timer Tick event after enabling timer in another class

I must be doing something completely wrong but I cannot figure it out. 我必须做一些完全错误的事情,但我无法弄清楚。 I have a form and I add in VS a timer control. 我有一个表单,我在VS中添加了一个计时器控件。 I also have a class that is watching for an application to start (notepad.exe). 我还有一个正在监视应用程序启动的类(notepad.exe)。 When the event arrives it is supposed to enable the timer, set the interval and on each tick do something (like firing a messagebox or changing a label). 当事件到达时,它应该启用计时器,设置间隔并在每个刻度上执行某些操作(例如触发消息框或更改标签)。 This seems not to be happening. 这似乎没有发生。 A look in the code make help someone give me a clue. 看看代码可以帮助别人给我一些线索。 The code is below: 代码如下:

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

}

And the watcher class is 守望者课程是

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");


    }
}

I noticed two things: 我注意到两件事:

When notepad.exe starts and I have the MessageBox.Show("notpad started"); 当notepad.exe启动时,我有MessageBox.Show("notpad started"); line commented out the messabox in the timer tick event won't fire. line注释掉计时器tick事件中的messabox不会触发。 If it is as displayed above it will show me both messageboxes (notepad started and tick). 如果它如上所示,它将显示两个消息框(记事本开始和勾选)。 However, the label1.Text will not change no matter what. 但是,无论如何, label1.Text都不会改变。

I am not sure what I am doing wrong. 我不确定我做错了什么。 I am sure it has something to do with how the timer event is handled but I am not sure what I should be doing. 我确信它与如何处理计时器事件有关,但我不确定我应该做什么。 Any ideas? 有任何想法吗?

Your code creates a new instance of Monitor. 您的代码创建了一个新的Monitor实例。 Thus you are not accessing the properties of the Monitor's instance you called eventWatch.WaitForProcessStart() in, so they're not changing. 因此,您不会访问名为eventWatch.WaitForProcessStart()的Monitor实例的属性,因此它们不会更改。 One way to solve this would be an event that is fired as soon as ProcessStarted() is fired. 解决此问题的一种方法是在触发ProcessStarted()时触发事件。 Your code could look like this: 您的代码可能如下所示:

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

}

It also looks like label1.Text will not change as you are running from a different thread. 它看起来像label1.Text不会因为从另一个线程运行而改变。 You would need to run an invoke on that label to update it from ManagementEventWatcher . 您需要在该标签上运行调用以从ManagementEventWatcher更新它。

Use this class: 使用这个类:

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"));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM