C# 在另一个类中启用计时器后调用计时器勾选事件

C# 在另一个类中启用计时器后调用计时器勾选事件,c#,timer,C#,Timer,我一定是做错了什么事,但我想不出来。我有一个表单,我添加了VS定时器控件。我还有一个类正在监视应用程序的启动(notepad.exe)。当事件到达时,应该启用计时器,设置时间间隔,并在每个刻度上执行一些操作(如触发messagebox或更改标签)。这似乎没有发生。看一下代码,让别人给我一个线索。代码如下: public partial class Monitor : Form { EventWatcher eventWatch = new EventWatcher(); Mana

我一定是做错了什么事,但我想不出来。我有一个表单,我添加了VS定时器控件。我还有一个类正在监视应用程序的启动(notepad.exe)。当事件到达时,应该启用计时器,设置时间间隔,并在每个刻度上执行一些操作(如触发messagebox或更改标签)。这似乎没有发生。看一下代码,让别人给我一个线索。代码如下:

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启动”)行注释掉定时器滴答事件中的messabox不会触发。如果如上所示,它将显示两个消息框(记事本已启动并勾选)。但是,无论发生什么情况,
标签1.Text
都不会更改


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

您的代码创建了一个新的Monitor实例。 因此,您没有访问在中调用eventWatch.WaitForProcessStart()的监视器实例的属性,因此它们没有更改。 解决此问题的一种方法是在激发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");
    }

}
类事件观察程序
{
公共事件事件处理程序已启动;
公共管理EventWatcher WatchForProcessStart(字符串processName)
{
字符串查询字符串=
“选择目标姿态”+
“来自_InstanceCreationEvent”+
“2以内”+
“其中TargetInstance ISA‘Win32_进程’”+
和TargetInstance.Name='“+processName+”;
//范围内的点表示使用当前机器
字符串范围=@“\\。\root\CIMV2”;
//创建观察者并侦听事件
ManagementEventWatcher watcher=新的ManagementEventWatcher(范围、查询字符串);
watcher.eventArrized+=OnProcessStarted;
watcher.Start();
返回观察者;
}
ProcessStarted上受保护的虚拟void(对象发送方,EventArrivedEventArgs e)
{
EventHandler copy=ProcessStarted;
如果(复制!=null)
复制(发送方,e);//触发事件
}
}
公共部分类监视器:窗体
{
EventWatcher eventWatch=新的EventWatcher();
ManagementEventWatcher startWatcher=新的ManagementEventWatcher();
ManagementEventWatcher endWatcher=新的ManagementEventWatcher();
公共监督员()
{
初始化组件();
startWatcher=eventWatch.WatchForProcessStart(“notepad.exe”);
startWatcher.ProcessStarted+=startWatcher_ProcessStarted;//订阅事件
endWatcher=eventWatch.WatchForProcessEnd(“notepad.exe”);
}
私有void startWatcher_进程已启动(对象发送方,EventArrivedEventArgs e)
{ 
监视器=新监视器();
//设置监视器类的计时器间隔和开始时间。(表格)
monitor.appTimer.Interval=5000;
monitor.appTimer.Enabled=true;
MessageBox.Show(“记事本启动”);
}
私有void appTimer_Tick(对象发送方,事件参数e)
{
标签1.Text=“勾选”;
MessageBox.Show(“勾选”);
}
}

它看起来也像
label1。当您从不同的线程运行时,文本不会更改。您需要在该标签上运行调用,以便从
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"));
使用系统;
使用System.Windows.Forms;
公共静态类控件扩展
{
///  
///在UI线程上异步执行操作,不阻止在调用线程上执行。
///  
///  
///  
公共静态void UIThread(此控件@this,操作代码)
{
如果(@this.invokererequired)
{
@此.BeginInvoke(代码);
}
其他的
{
code.Invoke();
}
}
}
并将'label1.Text=“tick”`替换为
this.UIThread(()=>this.label1.Text=“tick”);

谢谢您的帮助,但它似乎没有任何不同。如果显示“notepad started”(记事本已启动)的消息框不存在,则其他消息框不会在股票代码中触发。标签在任何一种情况下都不会改变,现在我得到了跨线程错误。我在怀疑你对这个新实例所说的话。将计时器设为静态字段不会解决此问题吗?但事实并非如此。从现在label1随着我的旧代码而改变的意义上看,这似乎工作得更好。但是,只有在ProcessStarted函数中有messagebox时,才会发生这种情况。