问题描述
我在FileSystemWatcher周围有一个Observable包装器。
public readonly FileSystemWatcher Watcher;
public ObservableFileSystemWatcher(FileSystemWatcher watcher)
{
if (watcher is null) throw new ArgumentNullException(nameof(watcher));
Watcher = watcher;
Changed = Observable
.FromEventPattern<FileSystemEventHandler,FileSystemEventArgs>(h => Watcher.Changed += h,h => Watcher.Changed -= h)
.Select(x => x.EventArgs);
Renamed = Observable
.FromEventPattern<RenamedEventHandler,RenamedEventArgs>(h => Watcher.Renamed += h,h => Watcher.Renamed -= h)
.Select(x => x.EventArgs);
Deleted = Observable
.FromEventPattern<FileSystemEventHandler,FileSystemEventArgs>(h => Watcher.Deleted += h,h => Watcher.Deleted -= h)
.Select(x => x.EventArgs);
Errors = Observable
.FromEventPattern<ErrorEventHandler,ErrorEventArgs>(h => Watcher.Error += h,h => Watcher.Error -= h)
.Select(x => x.EventArgs);
Created = Observable
.FromEventPattern<FileSystemEventHandler,FileSystemEventArgs>(h => Watcher.Created += h,h => Watcher.Created -= h)
.Select(x => x.EventArgs);
}
在这样的ApplicationContext(托盘程序)中观察到所说的Observable:
private void Watchers_Start()
{
_filesystemwatchers?.Clear();
foreach (var path in _pathstocheck)
{
try
{
ObservableFileSystemWatcher fsw = new ObservableFileSystemWatcher(c => { c.Path = path; c.IncludeSubdirectories = false; });
fsw.Created
.Where(_ => _.ChangeType is WatcherChangeTypes.Created)
.Select(_ => _.FullPath)
.Where(_ => !Path.GetFileName(_).StartsWith("~"))
.Where(File.Exists)
.Where(_ => ((DateTime.UtcNow - new DateTime(_lastFilesystem_Event)).TotalSeconds > _minDelayInSec))
.distinctUntilChanged()
.Subscribe(Filesystem_Event);
fsw.Errors.Subscribe(x => LogMsg($"ObservableFileSystemWatcher().Error {x.GetException().Message}",true));
_filesystemwatchers.Add(fsw);
fsw.Start();
}
catch (Exception exc) when (LogMsg(exc)) { }
}
}
private void Filesystem_Event(string flPath)
{
try
{
if (_playSound)
PlaySound();
if (_openPopup)
OpenPopup($"{DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss")}{Environment.NewLine} blahblah",flPath);
}
catch (Exception ex) when (LogMsg(ex)) { }
}
依次调用以下内容以向用户显示表单(PopupForm只是常规表单):
private void OpenPopup(string message,string filepath = "")
{
if (message is null) message = string.Empty;
LogMsg($"OpenPopup({message})");
_popupWindow = new PopupForm();
_popupWindow.Show();
}
好吧,如果我从ApplicationContext的任务栏图标上单击鼠标右键,然后选择显示测试通知,则它可以正常工作。这只是常规的C#事件。
_notifyIcon.ContextMenu = new ContextMenu(new MenuItem[]
{
new MenuItem("Riavvia",new EventHandler(RestartEventHandler)),new MenuItem("Configura",new EventHandler(ShowConfig)),new MenuItem("Test Audio",new EventHandler(PlayTestSound)),new MenuItem("Test Popup",new EventHandler(OpenTestPopup)),new MenuItem("Test Email",new EventHandler(SendTestemail)),new MenuItem("Test Errore",new EventHandler(SendTestException)),new MenuItem("Esci",new EventHandler(Exit))
});
/// which in turn calls
private void OpenTestPopup(object sender,EventArgs e)
{
OpenPopup("TEST POPUP");
}
一切正常!
但是,如果我使用的是FileSystemWatcher调用OpenPopup方法(在文件系统事件上)的方法,则该表单将无法完全绘制。
我感觉到SynchronizationContext问题或死锁问题,或两者兼而有之。 在序列完成之前,Observable可能不会完全返回吗? 如果我选择显示一个普通的MessageBox(使我感到困惑),则上述情况不会发生。
我已经尝试过:
- 将ObservableFileSystemWatcher强制使用其他调度程序
- 将ApplicationContext的SynchronizationContext传递给ObservableFileSystemWatcher
- 强制ObservableFileSystemWatcher在Scheduler.CurrentThread上运行
修改 我理解Panagiotis Kanavos想要说的是,在另一个线程上观察,然后在UI线程中 subscribe 。我的问题是,ApplicationContext不是UI,它只能启动表单(它是一个托盘图标)。
如果我以这种方式重构ObservableFileSystemWatcher,
public ObservableFileSystemWatcher(FileSystemWatcher watcher)
{
if (watcher is null) throw new ArgumentNullException(nameof(watcher));
Watcher = watcher;
Changed = Observable
.FromEventPattern<FileSystemEventHandler,h => Watcher.Changed -= h)
.ObserveOn(NewThreadScheduler.Default)
.Select(x => x.EventArgs);
// blabla
}
这样观察它
.SubscribeOn(dispatcherScheduler.Current)
我(理应如此)得到一个InvalidOperationException “当前线程没有与之关联的dispatcher。” 因为ApplicationContext不是WinForm。
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)