0

我正在尝试练习文件监视的示例。所以基本思想是创建一个独立的线程来监控被监视文件夹中的任何事件。原始程序是基于 windows 窗体的,我正在尝试将其转换为框架 3.5、C# + WPF;

响应事件的委托函数在 A.cs 中定义,它们看起来像:

public class WatcherEx : IDisposable
    {
        #region Data Members
        private bool           disposed    = false;
        private WatcherInfo    watcherInfo = null;
        private WatchersExList watchers    = new WatchersExList();
        #endregion Data Members

        #region Event Definitions
        public event WatcherExEventHandler EventChangedAttribute     = delegate {};
        public event WatcherExEventHandler EventChangedCreationTime  = delegate {};
        public event WatcherExEventHandler EventChangedDirectoryName = delegate {};
        public event WatcherExEventHandler EventChangedFileName      = delegate {};
        public event WatcherExEventHandler EventChangedLastAccess    = delegate {};
        public event WatcherExEventHandler EventChangedLastWrite     = delegate {};
        public event WatcherExEventHandler EventChangedSecurity      = delegate {};
        public event WatcherExEventHandler EventChangedSize          = delegate {};
        public event WatcherExEventHandler EventCreated              = delegate {};
        public event WatcherExEventHandler EventDeleted              = delegate {};
        public event WatcherExEventHandler EventRenamed              = delegate {};
        public event WatcherExEventHandler EventError                = delegate {};
        public event WatcherExEventHandler EventDisposed             = delegate {};
        public event WatcherExEventHandler EventPathAvailability     = delegate {};
        #endregion Event Definitions

        #region Constructors
        //--------------------------------------------------------------------------------
        public WatcherEx(WatcherInfo info)
        {
            if (info == null)
            {
                throw new Exception("WatcherInfo object cannot be null");
            }
            this.watcherInfo = info;

            Initialize();
        }
        #endregion Constructors

        #region Dispose Methods
        //--------------------------------------------------------------------------------
        /// <summary>
        /// Disposes all of the FileSystemWatcher objects, and disposes this object.
        /// </summary>
        public void Dispose()
        {
            Debug.WriteLine("WatcherEx.Dispose()");
            if (!this.disposed)
            {
                DisposeWatchers();
                this.disposed = true;
                GC.Collect();
                GC.WaitForPendingFinalizers();
            }
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Disposes of all of our watchers (called from Dispose, or as a result of 
        /// loosing access to a folder)
        /// </summary>
        public void DisposeWatchers()
        {
            Debug.WriteLine("WatcherEx.DisposeWatchers()");
            for (int i = 0; i < this.watchers.Count; i++)
            {
                this.watchers[i].Dispose();
            }
            this.watchers.Clear();
        }
        #endregion Dispose Methods

        #region Helper Methods
        //--------------------------------------------------------------------------------
        /// <summary>
        /// Determines if the specified NotifyFilter item has been specified to be 
        /// handled by this object.
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public bool HandleNotifyFilter(NotifyFilters filter)
        {
            return (((NotifyFilters)(this.watcherInfo.ChangesFilters & filter)) == filter);
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Determines if the specified WatcherChangeType item has been specified to be 
        /// handled by this object.
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public bool HandleWatchesFilter(WatcherChangeTypes filter)
        {
            return (((WatcherChangeTypes)(this.watcherInfo.WatchesFilters & filter)) == filter);
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Initializes this oibject by creating all of the required internal 
        /// FileSystemWatcher objects necessary to mointor the folder/file for the 
        /// desired changes
        /// </summary>
        private void Initialize()
        {
            Debug.WriteLine("WatcherEx.Initialize()");
            // the buffer can be from 4 to 64 kbytes.  Default is 8
            this.watcherInfo.BufferKBytes = Math.Max(4, Math.Min(this.watcherInfo.BufferKBytes, 64));

            // create the main watcher (handles create/delete, rename, error, and dispose)
            // can't pass a null enum type, so we just pass ta dummy one on the first call
            CreateWatcher(false, this.watcherInfo.ChangesFilters);
            // create a change watcher for each NotifyFilter item
            CreateWatcher(true, NotifyFilters.Attributes);
            CreateWatcher(true, NotifyFilters.CreationTime);
            CreateWatcher(true, NotifyFilters.DirectoryName);
            CreateWatcher(true, NotifyFilters.FileName);
            CreateWatcher(true, NotifyFilters.LastAccess);
            CreateWatcher(true, NotifyFilters.LastWrite);
            CreateWatcher(true, NotifyFilters.Security);
            CreateWatcher(true, NotifyFilters.Size);

            Debug.WriteLine(string.Format("WatcherEx.Initialize() - {0} watchers created", this.watchers.Count));
        }


        //--------------------------------------------------------------------------------
        /// <summary>
        /// Actually creates the necessary FileSystemWatcher objects, depending oin which 
        /// notify filters and change types the user specified.
        /// </summary>
        /// <param name="changeType"></param>
        /// <param name="filter"></param>
        private void CreateWatcher(bool changedWatcher, NotifyFilters filter)
        {
            Debug.WriteLine(string.Format("WatcherEx.CreateWatcher({0}, {1})", changedWatcher.ToString(), filter.ToString()));

            FileSystemWatcherEx watcher = null;
            int bufferSize = (int)this.watcherInfo.BufferKBytes * 1024;
            // Each "Change" filter gets its own watcher so we can determine *what* 
            // actually changed. This will allow us to react only to the change events 
            // that we actually want.  The reason I do this is because some programs 
            // fire TWO events for  certain changes. For example, Notepad sends two 
            // events when a file is created. One for CreationTime, and one for 
            // Attributes.
            if (changedWatcher)
            {
                // if we're not handling the currently specified filter, get out
                if (HandleNotifyFilter(filter))
                {
                    watcher                       = new FileSystemWatcherEx(this.watcherInfo.WatchPath);
                    watcher.IncludeSubdirectories = this.watcherInfo.IncludeSubFolders;
                    watcher.Filter                = this.watcherInfo.FileFilter;
                    watcher.NotifyFilter          = filter;
                    watcher.InternalBufferSize    = bufferSize;
                    switch (filter)
                    {
                        case NotifyFilters.Attributes    :
                            watcher.Changed += new FileSystemEventHandler(watcher_ChangedAttribute);
                            break;
                        case NotifyFilters.CreationTime  : 
                            watcher.Changed += new FileSystemEventHandler(watcher_ChangedCreationTime);
                            break;
                        case NotifyFilters.DirectoryName : 
                            watcher.Changed += new FileSystemEventHandler(watcher_ChangedDirectoryName);
                            break;
                        case NotifyFilters.FileName      : 
                            watcher.Changed += new FileSystemEventHandler(watcher_ChangedFileName);
                            break;
                        case NotifyFilters.LastAccess    : 
                            watcher.Changed += new FileSystemEventHandler(watcher_ChangedLastAccess);
                            break;
                        case NotifyFilters.LastWrite     : 
                            watcher.Changed += new FileSystemEventHandler(watcher_ChangedLastWrite);
                            break;
                        case NotifyFilters.Security      : 
                            watcher.Changed += new FileSystemEventHandler(watcher_ChangedSecurity);
                            break;
                        case NotifyFilters.Size          : 
                            watcher.Changed += new FileSystemEventHandler(watcher_ChangedSize);
                            break;
                    }
                }
            }
            // All other FileSystemWatcher events are handled through a single "main" 
            // watcher.
            else
            {
                if (HandleWatchesFilter(WatcherChangeTypes.Created) ||
                    HandleWatchesFilter(WatcherChangeTypes.Deleted) ||
                    HandleWatchesFilter(WatcherChangeTypes.Renamed) ||
                    this.watcherInfo.WatchForError ||
                    this.watcherInfo.WatchForDisposed)
                {
                    watcher                       = new FileSystemWatcherEx(this.watcherInfo.WatchPath, watcherInfo.MonitorPathInterval);
                    watcher.IncludeSubdirectories = this.watcherInfo.IncludeSubFolders;
                    watcher.Filter                = this.watcherInfo.FileFilter;
                    watcher.InternalBufferSize    = bufferSize;
                }

                if (HandleWatchesFilter(WatcherChangeTypes.Created)) 
                {
                    watcher.Created += new FileSystemEventHandler(watcher_CreatedDeleted);
                }
                if (HandleWatchesFilter(WatcherChangeTypes.Deleted))
                {
                    watcher.Deleted += new FileSystemEventHandler(watcher_CreatedDeleted);
                }
                if (HandleWatchesFilter(WatcherChangeTypes.Renamed))
                {
                    watcher.Renamed += new RenamedEventHandler(watcher_Renamed);
                }
                if (watcherInfo.MonitorPathInterval > 0)
                {
                    watcher.EventPathAvailability += new PathAvailabilityHandler(watcher_EventPathAvailability);
                }
            }
            if (watcher != null)
            {
                if (this.watcherInfo.WatchForError)
                {
                    watcher.Error += new ErrorEventHandler(watcher_Error);
                }
                if (this.watcherInfo.WatchForDisposed)
                {
                    watcher.Disposed += new EventHandler(watcher_Disposed);
                }
                this.watchers.Add(watcher);
            }
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Starts all of the internal FileSystemWatcher objects by setting their 
        /// EnableRaisingEvents property to true.
        /// </summary>
        public void Start()
        {
            Debug.WriteLine("WatcherEx.Start()");
            this.watchers[0].StartFolderMonitor();
            for (int i = 0; i < this.watchers.Count; i++)
            {
                this.watchers[i].EnableRaisingEvents = true;
            }
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Stops all of the internal FileSystemWatcher objects by setting their 
        /// EnableRaisingEvents property to true.
        /// </summary>
        public void Stop()
        {
            Debug.WriteLine("WatcherEx.Stop()");
            this.watchers[0].StopFolderMonitor();
            for (int i = 0; i < this.watchers.Count; i++)
            {
                this.watchers[i].EnableRaisingEvents = false;
            }
        }
        #endregion Helper Methods

        #region Native Watcher Events
        //--------------------------------------------------------------------------------
        /// <summary>
        /// Fired when the watcher responsible for monitoring attribute changes is 
        /// triggered.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void watcher_ChangedAttribute(object sender, FileSystemEventArgs e)
        {
            Debug.WriteLine("EVENT - Changed Attribute");
            EventChangedAttribute(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.FileSystem, NotifyFilters.Attributes));
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Fired when the watcher responsible for monitoring creation time changes is 
        /// triggered.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void watcher_ChangedCreationTime(object sender, FileSystemEventArgs e)
        {
            Debug.WriteLine("EVENT - Changed CreationTime");
            EventChangedCreationTime(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.FileSystem, NotifyFilters.CreationTime));
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Fired when the watcher responsible for monitoring directory name changes is 
        /// triggered.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void watcher_ChangedDirectoryName(object sender, FileSystemEventArgs e)
        {
            Debug.WriteLine("EVENT - Changed DirectoryName");
            EventChangedDirectoryName(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.FileSystem, NotifyFilters.DirectoryName));
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Fired when the watcher responsible for monitoring file name changes is 
        /// triggered.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void watcher_ChangedFileName(object sender, FileSystemEventArgs e)
        {
            Debug.WriteLine("EVENT - Changed FileName");
            EventChangedFileName(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.FileSystem, NotifyFilters.FileName));
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Fired when the watcher responsible for monitoring last access date/time 
        /// changes is triggered.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void watcher_ChangedLastAccess(object sender, FileSystemEventArgs e)
        {
            Debug.WriteLine("EVENT - Changed LastAccess");
            EventChangedLastAccess(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.FileSystem, NotifyFilters.LastAccess));
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Fired when the watcher responsible for monitoring last write date/time 
        /// changes is triggered.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void watcher_ChangedLastWrite(object sender, FileSystemEventArgs e)
        {
            Debug.WriteLine("EVENT - Changed LastWrite");
            EventChangedLastWrite(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.FileSystem, NotifyFilters.LastWrite));
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Fired when the watcher responsible for monitoring security changes is 
        /// triggered.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void watcher_ChangedSecurity(object sender, FileSystemEventArgs e)
        {
            Debug.WriteLine("EVENT - Changed Security");
            EventChangedSecurity(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.FileSystem, NotifyFilters.Security));
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Fired when the watcher responsible for monitoring size changes is 
        /// triggered.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void watcher_ChangedSize(object sender, FileSystemEventArgs e)
        {
            Debug.WriteLine("EVENT - Changed Size");
            EventChangedSize(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.FileSystem, NotifyFilters.Size));
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Fired when an internal watcher is disposed
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void watcher_Disposed(object sender, EventArgs e)
        {
            Debug.WriteLine("EVENT - Disposed");
            EventDisposed(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.StandardEvent));
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Fired when the main watcher detects an error (the watcher that detected the 
        /// error is part of the event's arguments object)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void watcher_Error(object sender, ErrorEventArgs e)
        {
            Debug.WriteLine("EVENT - Error");
            EventError(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.Error));
        }

        //--------------------------------------------------------------------------------
        /// <summary>
        /// Fired when the main watcher detects a file rename.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void watcher_Renamed(object sender, RenamedEventArgs e)
        {
            Debug.WriteLine("EVENT - Renamed");
            EventRenamed(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.Renamed));
        }

        //--------------------------------------------------------------------------------
        private void watcher_CreatedDeleted(object sender, FileSystemEventArgs e)
        {
            switch (e.ChangeType)   
            {
                case WatcherChangeTypes.Created :
                    Debug.WriteLine("EVENT - Created");
                    EventCreated(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.FileSystem));
                    break;
                case WatcherChangeTypes.Deleted :
                    Debug.WriteLine("EVENT - Changed Deleted");
                    EventDeleted(this, new WatcherExEventArgs(sender as FileSystemWatcherEx, e, ArgumentType.FileSystem));
                    break;
            }
        }

......

在另一个文件 B.cs(主 UI)中,我试图调用这些在 A.cs 中定义的事件响应函数,使用如下所示:

void fileWatcher_EventCreated(object sender, WatcherExEventArgs e)
        {
            listView1.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, _fileWatcher.EventCreated());
    }

但是我不断收到错误消息,说_fileWatcher.EventCreated()只能在 += 或 -=... 的左侧

我试图在 B.cs(UI 的 CS 文件)中完成所有操作,如下所示:

void fileWatcher_EventDeleted(object sender, WatcherExEventArgs e)
        {
            Action EventDeleted = delegate()
            {
                _lvie.fileName = ((FileSystemEventArgs)(e.Arguments)).FullPath;
                _lvie.fileEvent = "Deleted";
                _lvie.timeOfOccurance = DateTime.Now.ToString("HH:mm:ss.fff");
                listView1.Items.Add(_lvie);
            };

            listView1.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, EventDeleted);            
        }

但它没有很好地响应文件更改事件。它似乎没有选择一些事件。

我只是想知道我应该怎么做:在主 UI(A.cs)中调用后台线程(B.cs)中的响应事件函数?或者我应该以任何其他方式做到这一点?任何建议都非常感谢。谢谢。我对CS很陌生,所以请原谅我的无知。

4

1 回答 1

2

事件只能从它们所在的类内部引发。

B 类不能引发 A 类中存在的事件。

您可以实现的最接近的解决方法是从类 A 中创建一个新的 API 函数,称为 - 例如 - “RaiseMyEvent”,它从类 A 中手动引发事件;从 B 类调用该函数。

public class A
{
    public event EventHandler MyEvent = null;

    public void RaiseMyEvent(EventArgs args)
    {
        var handler = MyEvent;
        if(handler != null)
        {
            handler(this, args);
        }
    }
}

//Then, from inside class B:
myInstanceOfA.RaiseMyEvent();  //This will cause A to raise its own event
于 2013-02-08T14:36:08.350 回答