通过显示表单订阅Observable不会绘制控件

问题描述

我在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");
}

一切正常!

normally_drawn_form

但是,如果我使用的是FileSystemWatcher调用OpenPopup方法(在文件系统事件上)的方法,则该表单将无法完全绘制。

abnormally_drawn_form

我感觉到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 (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...