Currently I'm re-writing an WPF APP with .NET7 and ReactiveUI. I love the ReactiveUI framework and how easy async stuff can be achieved. However I'm struggling to binding an image. I keep getting a TargetInvocationException.
My idea is to have an async ReactiveCommand
that uses the LoadImageFromUrl
Akavache extension and expose the result through a OAPH
.
The ViewModel looks like the following:
public sealed class PartViewModel : ReactiveObject, IActivatableViewModel
{
private string? ImageUrl => Part.ImageUrl;
public ViewModelActivator Activator { get; } = new();
public PartDto Part { get; set; }
private readonly ObservableAsPropertyHelper<IBitmap?> _image;
public IBitmap? Image => _image.Value;
public PartSummaryViewModel(PartDto partDto)
{
Part = partDto;
var loadImage = ReactiveCommand
.CreateFromTask(LoadImageAsync);
_image = loadImage
.ToProperty(this, vm => vm.Image, scheduler: RxApp.MainThreadScheduler);
this.WhenActivated(disposables =>
{
loadImage
.Execute()
.Subscribe()
.DisposeWith(disposables);
});
}
private async Task<IBitmap?> LoadImageAsync(CancellationToken ct)
{
if (string.IsNullOrEmpty(ImageUrl))
{
return null;
}
var bitmap = await BlobCache.LocalMachine.LoadImageFromUrl(ImageUrl);
return bitmap;
}
}
The View looks like the following:
public partial class PartView : ReactiveUserControl<PartViewModel>
{
public PartView()
{
InitializeComponent();
this.WhenActivated(disposables =>
{
this.OneWayBind(ViewModel,
vm => vm.Image,
v => v.PartImage.Source,
(IBitmap? bitmap) => bitmap?.ToNative())
.DisposeWith(disposables);
});
}
}
The exception message I receive says:
*v.PartImage.Source Binding received an Exception! <s:ReactiveUI.PropertyBinderImplementation>
System.Reflection.TargetInvocationException:
Exception has been thrown by the target of an invocation.
---> System.InvalidOperationException:
The calling thread cannot access this object because a different thread owns it.*
I also tried to set the outputScheduler on the ReactiveCommand like so
var loadImage = ReactiveCommand
.CreateFromTask(LoadImageAsync, outputScheduler: RxApp.MainThreadScheduler);
But this results in the same exception.
I also tried to specify the scheduler in the WhenActivated
-part but get the same exception
loadImage
.Execute()
.ObserveOn(RxApp.MainThreadScheduler)
.Subscribe()
.DisposeWith(disposables);
Any idea what I'm missing?