Спасибо @GlennWatson за указание на то, что мне нужно добавить ссылку на пакет Nuget ReactiveUI.WPF в дополнение к пакету 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>) и не согласуется с каким-либо другим примером! Спасибо.
ОБНОВИТЬ
Спасибо @GlennWatson за указание на то, что мне нужно добавить ссылку на пакет Nuget ReactiveUI.WPF в дополнение к пакету 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;
}
}
}
ОБНОВИТЬ
У меня также была указанная ниже ошибка, вызванная тем же отсутствующим пакетом ... This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread
@RobinBennett Спасибо за ваш комментарий ... однако во время моего Googleathon я наткнулся на этот комментарий (в конце сообщения) Пола Беттса, автора ReactiveUI, который сказал, что это неправильный способ делать это! stackoverflow.com/a/16596310/5040941. Я просто не могу понять, как экстраполировать его фактический ответ (выше этого сообщения), чтобы он соответствовал моему сценарию. Кроме того, его ответ датирован 2013 годом, и у меня сложилось впечатление, что ReactiveUI достаточно изменился, и теперь есть более эффективные способы.
Достаточно справедливо - я должен был упомянуть, что ничего не знаю о ReactiveUI!
: 0) ты не единственный \ 0 / !!
На какой платформе вы работаете? У вас часто возникают проблемы с потоковой передачей, если вы не включаете нужные пакеты NuGet. Например, reactiveui.wpf
Избегайте абстрактного базового класса. Используйте ReactiveCommand <Unit, Unit>
@GlennWatson. Просто добавил ссылку на пакет nuget reactiveui.wpf, и он сразу заработал! Если вы измените свой комментарий на ответ, я сразу его приму!
Боже мой, я просто ударил головой из-за этого. Слава богу за этот вопрос и ответ.





Если вы работаете на платформе WPF или WinForms, вам необходимо убедиться, что вы включили ссылку nuget на ReactiveUI.WPF или ReactiveUI.Winforms.
Еще раз спасибо, Гленн. Я выделил это в начале своего вопроса, потому что кажется, что это может исправить гораздо больше, чем мою проблему с OpenFileDialog! : 0)
Часто решение такой проблемы состоит в том, чтобы заключить строку, вызывающую проблему, в Application.Current.Dispatcher.Invoke ().