ReactiveUI WPF - 调用线程无法访问此对象,因为另一个线程拥有它

ReactiveUI WPF - The calling thread cannot access this object because a different thread owns it

感谢@GlennWatson 指出除了 ReactiveUI 包之外,我还需要添加对 Nuget 包 ReactiveUI.WPF 的引用。

我有一个 ReactiveObject 视图模型,我想在其中使用 OpenFileDialog 来设置我的视图模型属性之一 (PdfFilePath) 的值。 我尝试的所有操作都会导致 The calling thread cannot access this object because a different thread owns it 错误。

我意识到下面的代码不符合 MVVM,因为我在视图模型中使用 'explicitly references the type of/instantiates the view' 的代码,但我只是在寻找一个可行的最小示例,以便我可以向后工作,拆分视图和视图模型代码分开,并最终将服务传递给我的视图模型来处理整个 'selecting a file path' 部分。

public class ImportPdfViewModel : ReactiveObject
{
    public ImportPdfViewModel()
    {
        SelectFilePathCommand = ReactiveCommand.Create(() =>
        {
            OpenFileDialog ofd = new OpenFileDialog() { };
            //
            if (ofd.ShowDialog() == DialogResult.OK)
                PdfFilePath = ofd.FileName;
        });
    }

    private string _PdfFilePath;
    public string PdfFilePath
    {
        get => _PdfFilePath;
        set => this.RaiseAndSetIfChanged(ref _PdfFilePath, value);
    }

    public ReactiveCommand SelectFilePathCommand { get; set; }
}

正如我所提到的,我尝试了很多不同的选择,包括将服务注入我的视图模型,但无论我在哪里实例化 OpenFileDialog(例如在主视图中),我总是以同样的错误。

我还用谷歌搜索了 "ReactiveUI" 和 "OpenFileDialog",但是我发现的 none 代码似乎是最新的(例如使用 ReactiveCommand<Unit, Unit>), 也不符合任何其他例子!谢谢。


更新

感谢@GlennWatson 指出除了 ReactiveUI 包之外,我还需要添加对 Nuget 包 ReactiveUI.WPF 的引用。

我一添加,代码就成功了!

代码现在看起来像这样,我相信它符合 MVVM,使用依赖注入,并使用 ReactiveUI 的最新 features/best 实践(尽管我显然愿意接受批评!):

ImportPdf

public class ImportPdfViewModel : ReactiveObject
{
    public ImportPdfViewModel(IIOService openFileDialogService)
    {
        SelectFilePathCommand = ReactiveCommand
            .Create(() => openFileDialogService.OpenFileDialog(@"C:\Default\Path\To\File"));
        SelectFilePathCommand.Subscribe((pdfFilePath) => { PdfFilePath = pdfFilePath; });
    }

    private string _PdfFilePath;
    public string PdfFilePath
    {
        get => _PdfFilePath;
        set => this.RaiseAndSetIfChanged(ref _PdfFilePath, value);
    }

    public ReactiveCommand<Unit, String> SelectFilePathCommand { get; set; }
}

IIOService

public interface IIOService
{
    string OpenFileDialog(string defaultPath);
}

OpenFileDialogService

public class OpenFileDialogService : IIOService
{
    public string OpenFileDialog(string defaultPath)
    {
        OpenFileDialog ofd = new OpenFileDialog() { FileName = defaultPath };
        //
        if (ofd.ShowDialog() == DialogResult.OK)
        {
            return ofd.FileName;
        }
        else
        {
            return null;
        }
    }
}

更新

我也遇到过由于相同的丢失包导致的以下错误...This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread

如果 运行 在 WPF 或 WinForms 平台上,您需要确保包含对 ReactiveUI.WPF 或 ReactiveUI.Winforms.

的 nuget 引用