Thanks to @GlennWatson for pointing out that I needed to add a reference to the Nuget Package ReactiveUI.WPF
, in addition to the ReactiveUI
package.
I have a ReactiveObject
view model, within which I would like to use an OpenFileDialog
to set the value of one of my view model properties (PdfFilePath
).
Everything I have tried results in a The calling thread cannot access this object because a different thread owns it
error.
I realise that the code below is not MVVM compliant because I am using code that 'explicitly references the type of/instantiates the view' in the view model, but I'm just looking for a minimal example that works so I can work backwards, splitting the view and view model code apart, and ultimately passing in a service to my view model that handles the whole 'selecting a file path' part.
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; }
}
As i mentioned, I have tried lots of different options, including injecting a service into my view model, but no matter where I instantiate the OpenFileDialog
(eg in the main view), I always end up with the same error.
I've also googled the hell out of "ReactiveUI" and "OpenFileDialog", but none of the code I find seems to be up to date (eg using ReactiveCommand<Unit, Unit>
), nor consistent with any other example! Thanks.
UPDATE
Thanks to @GlennWatson for pointing out that I needed to add a reference to the Nuget Package ReactiveUI.WPF
, in addition to the ReactiveUI
package.
As soon as I added it, the code worked!
The code now looks like this, which I believe is MVVM compliant, uses dependency injection, and uses the latest features/best practices of ReactiveUI (though I'm obviously open to criticism!):
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
I've also had the error below caused by the same missing package ... This type of CollectionView does not support changes to its SourceCollection from a thread different from the Dispatcher thread
reactiveui.wpf
and it worked straight away! If you change your comment to an answer I'll accept it straight away! – Amnesty