Hello!
I have an application with a simple view which contains only a button
<Button Command={Binding TestCommand}/>
The TestCommand property of the DataContext is a
TestCommand = ReactiveCommand.Create(() => {});
The AppBuilder inside Main method looks like this.
...
var context = new ApplicationContext();
AppBuilder
.Configure(app)
.UsePlatformDetect()
.UseReactiveUI()
.Start<MainWindow>(() => context); // The problem is here.
With this code, when i click the button my application crashes with
System.InvalidOperationException: Call from invalid thread
I can fix this by changing AppBuilder chain with
...
.Start<MainWindow>(() => new ApplicationContext());
However, I really would like to create ApplicationContext before calling the AppBuilder. Can I actually do this?
What is ApplicationContext and what does .Start<MainWindow>(() => context); do?
I have uploaded the application which reproduces the error -
https://github.com/stdcall/Avalonia-Hello
You shouldn't use any Avalonia APIs before either SetupWithoutStarting or Start<TWindow> is called on AppBuilder. The same goes for RxUI, since it needs to use Avalonia's synchronization primitives which are not available before setup.
@stdcall In addition, I'd like to mention that writing such code at the beginning of your Main method will likely do the trick:
public void Main(string[] args)
{
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; // Interesting line of code that fixes the issue!
var context = new ApplicationContext();
AppBuilder
.Configure(app)
.UsePlatformDetect()
.Start<MainWindow>(() => context);
}
The UseReactiveUI method actually initializes the ReactiveUI main thread scheduler using a static instance of the AvaloniaScheduler. Why are you getting that InvalidOperationException? 'Cause you are trying to create your ReactiveUI ViewModel when things haven't been initialized yet. So, if you initialize the schedulers by hands, the exception will go away.
But I'd not recommend you doing so - let the fameworks initialize the things for you.
So this is the best way to go at this time:
.UseReactiveUI()
.Start<MainWindow>(() => new ApplicationContext());
Most helpful comment
You shouldn't use any Avalonia APIs before either
SetupWithoutStartingorStart<TWindow>is called on AppBuilder. The same goes for RxUI, since it needs to use Avalonia's synchronization primitives which are not available before setup.