This repository was archived by the owner on Jan 23, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 4.8k
Add missing FileSystemWatcher methods #13656
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,6 +3,7 @@ | |
| // See the LICENSE file in the project root for more information. | ||
|
|
||
| using System.ComponentModel; | ||
| using System.ComponentModel.Design; | ||
| using System.Diagnostics; | ||
| using System.Diagnostics.CodeAnalysis; | ||
| using System.Threading; | ||
|
|
@@ -15,7 +16,7 @@ namespace System.IO | |
| /// raises events when a directory or file within a directory changes. | ||
| /// </devdoc> | ||
|
|
||
| public partial class FileSystemWatcher : Component | ||
| public partial class FileSystemWatcher : Component, ISupportInitialize | ||
| { | ||
| /// <devdoc> | ||
| /// Private instance variables | ||
|
|
@@ -36,11 +37,15 @@ public partial class FileSystemWatcher : Component | |
| // Flag to note whether we are attached to the thread pool and responding to changes | ||
| private bool _enabled = false; | ||
|
|
||
| // Are we in init? | ||
| private bool _initializing = false; | ||
|
|
||
| // Buffer size | ||
| private int _internalBufferSize = 8192; | ||
|
|
||
| // Used for synchronization | ||
| private bool _disposed; | ||
| private ISynchronizeInvoke _synchronizingObject; | ||
|
|
||
| // Event handlers | ||
| private FileSystemEventHandler _onChangedHandler = null; | ||
|
|
@@ -146,14 +151,21 @@ public bool EnableRaisingEvents | |
| { | ||
| return; | ||
| } | ||
|
|
||
| if (value) | ||
| if (IsSuspended()) | ||
| { | ||
| StartRaisingEventsIfNotDisposed(); // will set _enabled to true once successfully started | ||
| _enabled = value; // Alert the Component to start watching for events when EndInit is called. | ||
| } | ||
| else | ||
| { | ||
| StopRaisingEvents(); // will set _enabled to false | ||
| { | ||
| if (value) | ||
| { | ||
| StartRaisingEventsIfNotDisposed(); // will set _enabled to true once successfully started | ||
| } | ||
| else | ||
| { | ||
| StopRaisingEvents(); // will set _enabled to false | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
@@ -371,6 +383,7 @@ protected override void Dispose(bool disposing) | |
| finally | ||
| { | ||
| _disposed = true; | ||
| base.Dispose(disposing); | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -446,7 +459,7 @@ private void NotifyFileSystemEventArgs(WatcherChangeTypes changeType, string nam | |
| [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#", Justification = "Changing from protected to private would be a breaking change")] | ||
| protected void OnChanged(FileSystemEventArgs e) | ||
| { | ||
| _onChangedHandler?.Invoke(this, e); | ||
| InvokeOn(e, _onChangedHandler); | ||
| } | ||
|
|
||
| /// <devdoc> | ||
|
|
@@ -455,7 +468,7 @@ protected void OnChanged(FileSystemEventArgs e) | |
| [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#", Justification = "Changing from protected to private would be a breaking change")] | ||
| protected void OnCreated(FileSystemEventArgs e) | ||
| { | ||
| _onCreatedHandler?.Invoke(this, e); | ||
| InvokeOn(e, _onCreatedHandler); | ||
| } | ||
|
|
||
| /// <devdoc> | ||
|
|
@@ -464,7 +477,19 @@ protected void OnCreated(FileSystemEventArgs e) | |
| [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#", Justification = "Changing from protected to private would be a breaking change")] | ||
| protected void OnDeleted(FileSystemEventArgs e) | ||
| { | ||
| _onDeletedHandler?.Invoke(this, e); | ||
| InvokeOn(e, _onDeletedHandler); | ||
| } | ||
|
|
||
| private void InvokeOn(FileSystemEventArgs e, FileSystemEventHandler handler) | ||
| { | ||
| if (handler != null) | ||
| { | ||
| ISynchronizeInvoke syncObj = SynchronizingObject; | ||
| if (syncObj != null && syncObj.InvokeRequired) | ||
| syncObj.BeginInvoke(handler, new object[] { this, e }); | ||
| else | ||
| handler(this, e); | ||
| } | ||
| } | ||
|
|
||
| /// <devdoc> | ||
|
|
@@ -473,7 +498,15 @@ protected void OnDeleted(FileSystemEventArgs e) | |
| [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#", Justification = "Changing from protected to private would be a breaking change")] | ||
| protected void OnError(ErrorEventArgs e) | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. InvokeOn(e, _onErrorHandler);
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I didn't use the |
||
| { | ||
| _onErrorHandler?.Invoke(this, e); | ||
| ErrorEventHandler handler = _onErrorHandler; | ||
| if (handler != null) | ||
| { | ||
| ISynchronizeInvoke syncObj = SynchronizingObject; | ||
| if (syncObj != null && syncObj.InvokeRequired) | ||
| syncObj.BeginInvoke(handler, new object[] { this, e }); | ||
| else | ||
| handler(this, e); | ||
| } | ||
| } | ||
|
|
||
| /// <devdoc> | ||
|
|
@@ -482,7 +515,15 @@ protected void OnError(ErrorEventArgs e) | |
| [SuppressMessage("Microsoft.Security", "CA2109:ReviewVisibleEventHandlers", MessageId = "0#", Justification = "Changing from protected to private would be a breaking change")] | ||
| protected void OnRenamed(RenamedEventArgs e) | ||
| { | ||
| _onRenamedHandler?.Invoke(this, e); | ||
| RenamedEventHandler handler = _onRenamedHandler; | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. InvokeOn(e, _onRenamedHandler); |
||
| if (handler != null) | ||
| { | ||
| ISynchronizeInvoke syncObj = SynchronizingObject; | ||
| if (syncObj != null && syncObj.InvokeRequired) | ||
| syncObj.BeginInvoke(handler, new object[] { this, e }); | ||
| else | ||
| handler(this, e); | ||
| } | ||
| } | ||
|
|
||
| public WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType) => | ||
|
|
@@ -566,7 +607,7 @@ public WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType, int ti | |
| /// <internalonly/> | ||
| private void Restart() | ||
| { | ||
| if (_enabled) | ||
| if ((!IsSuspended()) && _enabled) | ||
| { | ||
| StopRaisingEvents(); | ||
| StartRaisingEventsIfNotDisposed(); | ||
|
|
@@ -580,5 +621,67 @@ private void StartRaisingEventsIfNotDisposed() | |
| throw new ObjectDisposedException(GetType().Name); | ||
| StartRaisingEvents(); | ||
| } | ||
|
|
||
| public override ISite Site | ||
| { | ||
| get | ||
| { | ||
| return base.Site; | ||
| } | ||
| set | ||
| { | ||
| base.Site = value; | ||
|
|
||
| // set EnableRaisingEvents to true at design time so the user | ||
| // doesn't have to manually. | ||
| if (Site != null && Site.DesignMode) | ||
| EnableRaisingEvents = true; | ||
| } | ||
| } | ||
|
|
||
| public ISynchronizeInvoke SynchronizingObject | ||
| { | ||
| get | ||
| { | ||
| if (_synchronizingObject == null && DesignMode) | ||
| { | ||
| IDesignerHost host = (IDesignerHost)GetService(typeof(IDesignerHost)); | ||
| if (host != null) | ||
| { | ||
| object baseComponent = host.RootComponent; | ||
| if (baseComponent != null && baseComponent is ISynchronizeInvoke) | ||
| _synchronizingObject = (ISynchronizeInvoke)baseComponent; | ||
| } | ||
| } | ||
|
|
||
| return _synchronizingObject; | ||
| } | ||
|
|
||
| set | ||
| { | ||
| _synchronizingObject = value; | ||
| } | ||
| } | ||
|
|
||
| public void BeginInit() | ||
| { | ||
| bool oldEnabled = _enabled; | ||
| StopRaisingEvents(); | ||
| _enabled = oldEnabled; | ||
| _initializing = true; | ||
| } | ||
|
|
||
| public void EndInit() | ||
| { | ||
| _initializing = false; | ||
| // Start listening to events if _enabled was set to true at some point. | ||
| if (_directory.Length != 0 && _enabled) | ||
| StartRaisingEvents(); | ||
| } | ||
|
|
||
| private bool IsSuspended() | ||
| { | ||
| return _initializing || DesignMode; | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When will the subsequent logic be invoked in this case?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It won't be. When under initialization, the only action StopRaisingEvents does is to set _enabled to false since actual event watching is paused/stopped/hasn't begun.
This state is reached by first called BeginInit() which will call StopRaisingEvents before setting _enabled, so before we get into an
IsSuspendedstate we will have done the subsequent cleanup necessary.So the assertion is that when
IsSuspendedis true, we already did the other stuff inStopRaisingEventsand don't need to do it again.This is ripped from the desktop code.