ReactiveUI WPF-调用线程无法访问该对象,因为其他线程拥有它

时间:2018-11-06 11:03:14

标签: c# mvvm reactive-programming reactiveui

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

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

我意识到下面的代码不符合MVVM,因为我使用的代码在视图模型中“明确引用了/实例化视图的类型”,但我只是在寻找一个可以正常工作的最小示例。向后工作,将视图和视图模型代码分开,最终将服务传递给我的视图模型,该服务处理整个“选择文件路径”部分。

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”搜索了地狱,但是我发现的代码似乎都不是最新的(例如,使用ReactiveCommand<Unit, Unit>),也与任何其他示例均不一致!谢谢。


UPDATE

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

我一添加它,代码就起作用了!

代码现在看起来像这样,我认为它符合MVVM,使用依赖注入,并使用ReactiveUI的最新功能/最佳实践(尽管我显然很容易受到批评!):

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;
        }
    }
}

UPDATE

我还遇到了以下错误,该错误是由于缺少相同的软件包而引起的... This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread

1 个答案:

答案 0 :(得分:3)

如果在WPF或WinForms平台上运行,则需要确保包含对ReactiveUI.WPF或ReactiveUI.Winforms的nuget引用。