由于 Novell,我刚刚发现我不能使用 FileSystemWatcher 来监视目录的内容更改,所以我必须实现自己的版本。除了我的实现可能效率低下这一事实之外,我遇到的问题之一是我的 UI 中的 ListBox 没有使用文件列表进行更新。
这是我的文件夹类:
public class FolderWatcher
{
// This collection will contain the files in the folder
public static AsyncObservableCollection<FileItem> folder = new AsyncObservableCollection<FileItem>();
// Timer
System.Timers.Timer timer;
// Path
string path;
// Extension type
string extension;
//The next line is important to allow system for us to monitor it. It's a trust setting, and we need Full Trust.
[PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
public void Run(string dirPath, string extensionFilter)
{
// Set path and extension
path = dirPath;
extension = extensionFilter;
// Populate the folder list with the current files
var dirInfo = new DirectoryInfo(path);
foreach (var currentFile in dirInfo.GetFiles())
{
var aFile = new FileItem
{
Name = currentFile.Name,
Path = currentFile.FullName
};
folder.Add(aFile);
}
// Start the timer
timer = new System.Timers.Timer(5000);
timer.AutoReset = true;
timer.Enabled = true;
// When timer elapses, raise an event
timer.Elapsed += new System.Timers.ElapsedEventHandler(UpdateFiles);
}
// Update Files
private void UpdateFiles(object sender, System.Timers.ElapsedEventArgs e)
{
// Get directory info
var dirInfo = new DirectoryInfo(path);
// Create a temporary list to hold new items
AsyncObservableCollection<FileItem> temp = new AsyncObservableCollection<FileItem>();
// Add the items into the temporary list
foreach (var currentFile in dirInfo.GetFiles())
{
var aFile = new FileItem
{
Name = currentFile.Name,
Path = currentFile.FullName
};
temp.Add(aFile);
}
// Check for new files first, checking if they've been renamed as well
int count = temp.Count;
for (int i = 0; i < count; i++)
{
// If main folder list doesn't contain a new file, add it
if (!folder.Contains(temp[i]))
{
folder.Add(temp[i]);
}
}
// Now check to see if any files have been removed
count = folder.Count;
for (int i = 0; i < count; i++)
{
// If temp folder doesn't contain these files, remove them
if (!temp.Contains(folder[i]))
{
folder.RemoveAt(i);
}
}
}
}
文件项:
public class FileItem : INotifyPropertyChanged
{
private string _Name;
public string Name
{
get
{
return _Name;
}
set
{
if (_Name != value)
{
_Name = value;
OnPropertyChanged("Name");
}
}
}
private string _Path;
public string Path
{
get { return _Path; }
set
{
if (_Path != value)
{
_Path = value;
OnPropertyChanged("Path");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(String propertyName)
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
public override string ToString()
{
return _Path;
}
}
修改后的 ObservableCollection:
public class AsyncObservableCollection<T> : ObservableCollection<T>
{
private SynchronizationContext _synchronizationContext = SynchronizationContext.Current;
public AsyncObservableCollection()
{
}
public AsyncObservableCollection(IEnumerable<T> list)
: base(list)
{
}
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
if (SynchronizationContext.Current == _synchronizationContext)
{
// Execute the CollectionChanged event on the current thread
RaiseCollectionChanged(e);
}
else
{
// Post the CollectionChanged event on the creator thread
_synchronizationContext.Post(RaiseCollectionChanged, e);
}
}
private void RaiseCollectionChanged(object param)
{
// We are in the creator thread, call the base implementation directly
base.OnCollectionChanged((NotifyCollectionChangedEventArgs)param);
}
protected override void OnPropertyChanged(PropertyChangedEventArgs e)
{
if (SynchronizationContext.Current == _synchronizationContext)
{
// Execute the PropertyChanged event on the current thread
RaisePropertyChanged(e);
}
else
{
// Post the PropertyChanged event on the creator thread
_synchronizationContext.Post(RaisePropertyChanged, e);
}
}
private void RaisePropertyChanged(object param)
{
// We are in the creator thread, call the base implementation directly
base.OnPropertyChanged((PropertyChangedEventArgs)param);
}
}
更新:上面是更新的代码。我只是在努力让它正确更新,但其他一切似乎都很好。我会在它功能齐全时进行更新,以便其他人可以使用。
我最终重写了我的旧代码,它变得失控并且难以管理。我决定简化它,现在它使用字符串,但可以很容易地用于我的 FileItem ......这是一个片段(它没有分成文件,因为这是一个测试应用程序):
public MainWindow()
{
// Must be used (read MSDN documentation)
InitializeComponent();
// Our main collection to hold names of files
this.dir = new ObservableCollection<string>();
// Bind our collection to the listbox as the source of data
TheListBox.ItemsSource = dir;
// Target directory path
dirInfo = new DirectoryInfo(@"C:\Temp");
// Set timer (2 seconds is optimal for overhead and quick updates... increase or decrease based on system performance)
timer = new System.Timers.Timer(2000);
timer.AutoReset = true;
timer.Enabled = true;
// Add an event handler for timer elapsing
timer.Elapsed += new System.Timers.ElapsedEventHandler(UpdateFiles);
}
// Updates Files in the directory collection
private void UpdateFiles(object sender, System.Timers.ElapsedEventArgs e)
{
// Temporary collection that will help us compare files and avoid errors
ObservableCollection<string> temp = new ObservableCollection<string>();
// Since we're using a timer, we have to invoke the changes into the main thread, or we'll get an access exception on dir
System.Windows.Application.Current.Dispatcher.Invoke(
DispatcherPriority.Normal,
(Action)delegate()
{
// Populate the temporary collection with files
foreach (var file in dirInfo.GetFiles())
{
if (!String.IsNullOrEmpty(file.ToString()))
{
try
{
temp.Add(file.ToString());
}
catch (Exception listE)
{
// log exception
}
}
}
// Check to see if there are any new files
foreach (var item in temp)
{
if (!dir.Contains(item.ToString()) && !String.IsNullOrEmpty(item.ToString()))
{
try
{
dir.Add(item.ToString());
}
catch (Exception listE)
{
// log exception
}
}
}
// Check to see if any files have been moved/renamed
for (int i = 0; i < dir.Count; i++)
{
if (!temp.Contains(dir[i].ToString()) && !String.IsNullOrEmpty(dir[i].ToString()))
{
try
{
dir.RemoveAt(i);
}
catch (Exception listE)
{
// log exception
}
}
}
});
}
它有效并且运作良好。没有错误,什么都没有。我敢肯定有办法让它更短,但这取决于你。我想我会与遇到类似问题的任何人分享这个。