65.9K
CodeProject 正在变化。 阅读更多。
Home

同步 Invoke 事件

starIconstarIconemptyStarIconemptyStarIconemptyStarIcon

2.00/5 (2投票s)

2009年4月15日

CPOL

1分钟阅读

viewsIcon

18435

downloadIcon

155

从不同线程安全地调用控件的方法。

引言

Windows 窗体中的控件绑定到特定线程,并且不是线程安全的。因此,如果您从不同线程调用控件的方法,则必须使用控件的 Invoke 方法之一,将调用传递到正确的线程。

背景

Windows 窗体使用单线程公寓 (STA) 模型,因为 Windows 窗体基于固有的公寓线程化的本机 Win32 窗口。STA 模型意味着可以在任何线程上创建窗口,但创建后不能切换线程,并且所有对它的函数调用都必须在其创建线程上发生。在 Windows 窗体之外,.NET Framework 中的类使用自由线程模型。

STA 模型要求,任何需要在控件的创建线程之外调用的控件上的方法都必须传递到(在控件的创建线程上执行)。基类 Control 提供了几种方法(InvokeBeginInvokeEndInvoke)来实现此目的。Invoke 进行同步方法调用,而 BeginInvoke 进行异步方法调用。

使用代码

使用属性 'InvokeRequired' 来指示调用者是否必须在对控件进行方法调用时调用 Invoke 方法,因为调用者位于与控件创建线程不同的线程上。

public static class Utility
{
    public static void SynchronizeInvokeEvent(object sender, 
                       Delegate TargetEvent, EventArgs e)
    {
        if (TargetEvent != null)
        {
            Delegate[] InvocationList = TargetEvent.GetInvocationList();
            foreach (Delegate TargetDelegate in InvocationList)
            {
                try
                {
                    System.ComponentModel.ISynchronizeInvoke Target = 
                           TargetDelegate.Target 
                           as System.ComponentModel.ISynchronizeInvoke;
                    if (Target != null)
                    {
                        if (Target.InvokeRequired)
                            Target.Invoke(TargetDelegate, new object[] { sender, e });
                        else
                            TargetDelegate.DynamicInvoke(new object[] { sender, e });
                    }
                    else
                    {
                        TargetDelegate.DynamicInvoke(new object[] { sender, e });
                    }
                }
                catch (Exception ex)
                {
                    throw ex;
                }
            }
        }
    }
} 

// You must add references to System.Management.dll
public class ProcessWatcher : IDisposable
{
    public delegate void TaskManagerEventHandler(object sender, 
                         TaskManagerEventArgs e);
    public event TaskManagerEventHandler ProcessCreated;
    private bool m_StartedWatcher;
    private System.Management.ManagementEventWatcher m_CreateProcessWatcher;
    public ProcessWatcher()
    {
        m_StartedWatcher = false;
    }
    public void Dispose()
    {
        StopWatcher();
        GC.Collect();
        GC.WaitForPendingFinalizers();
    }
    public void StartWatcher()
    {
        if (m_StartedWatcher)
            return;
        m_StartedWatcher = true;
        System.Management.EventWatcherOptions eventOptions = 
           new System.Management.EventWatcherOptions();
        eventOptions.BlockSize = 1;
        eventOptions.Timeout = new TimeSpan(0, 0, 2);
        m_CreateProcessWatcher = new System.Management.ManagementEventWatcher
            (
                "root\\CIMV2",
                "SELECT * FROM __InstanceCreationEvent WITHIN 1 " + 
                "WHERE TargetInstance ISA \"Win32_Process\"",
                eventOptions
            );
        m_CreateProcessWatcher.EventArrived += 
          new System.Management.EventArrivedEventHandler(
          OnCreateProcessWatcher_EventArrived);
        m_CreateProcessWatcher.Start();
    }
    public void StopWatcher()
    {
        if (!m_StartedWatcher)
            return;
        m_StartedWatcher = false;
        m_CreateProcessWatcher.Stop();
        m_CreateProcessWatcher.EventArrived -= 
          new System.Management.EventArrivedEventHandler(
          OnCreateProcessWatcher_EventArrived);
        m_CreateProcessWatcher.Dispose();
        m_CreateProcessWatcher = null;
    }
    void OnCreateProcessWatcher_EventArrived(object sender, 
         System.Management.EventArrivedEventArgs e)
    {
        int ProcessID;
        if (int.TryParse(((System.Management.ManagementBaseObject)
            e.NewEvent["TargetInstance"])["ProcessId"].ToString(), 
            out ProcessID))
        {
            OnCreateProcess(new TaskManagerEventArgs(
              System.Diagnostics.Process.GetProcessById(ProcessID)));
        }
    }
    private void OnCreateProcess(TaskManagerEventArgs e)
    {
        Utility.SynchronizeInvokeEvent(this, ProcessCreated, e);
    }
    public class TaskManagerEventArgs : EventArgs
    {
        private System.Diagnostics.Process m_Process;
        public TaskManagerEventArgs(System.Diagnostics.Process Process)
        {
            m_Process = Process;
        }
        public System.Diagnostics.Process Process
        {
            get { return m_Process; }
        }
    }
} 

public partial class Form1 : Form
{
    private ProcessWatcher m_ProcessWatcher;
    public Form1()
    {
        InitializeComponent();
        m_ProcessWatcher = new ProcessWatcher();
        m_ProcessWatcher.ProcessCreated += new 
          ProcessWatcher.TaskManagerEventHandler(
          m_ProcessWatcher_ProcessCreated);
    }
    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        // Dispose ProcessWatcher here or in form disposing method;
        m_ProcessWatcher.Dispose();
        base.OnFormClosing(e);
    }
    private void m_ProcessWatcher_ProcessCreated(object sender, 
                 ProcessWatcher.TaskManagerEventArgs e)
    {
        this.listBox1.Items.Add(e.Process.ProcessName);
    }
    private void m_StartProcessWatcherButton_Click(object sender, EventArgs e)
    {
        m_ProcessWatcher.StartWatcher();
    }
    private void m_StopProcessWatcherButton_Click(object sender, EventArgs e)
    {
        m_ProcessWatcher.StopWatcher();
    }
}
© . All rights reserved.