I am currently working on a Login-Window, which should be responsible for establishing a connection to a server, verify user credentials and then open a MVVM 'MainWindow'. I want to speed up the opening process of my MainWindow a little, which is why I am trying to transfer the Initialization of its ViewModel in an own Task. This somehow broke my Commands and I cannot understand why, so I created a minimal reproducible example to explain my problems.
The ViewModel looks like this:
public class MainWindowViewModel
{
public MainWindowViewModel()
{
}
public ICommand ClickCommand { get; set; }
public void CreateCommands()
{
ClickCommand = new RelayCommand(ExecuteClick);
}
public void ExecuteClick()
{
}
The View is just a default window with a button that has a command binding: Command="{Binding ClickCommand}"
I create view and viewmodel and call CreateCommands from within a Task, which works.
MainWindow mw = new MainWindow();
MainWindowViewModel vm = new MainWindowViewModel();
mw.DataContext = vm;
Task.Run(() =>
{
vm.CreateCommands();
});
mw.ShowDialog();
now I create a new Method Init() in my View and have it call CreateCommands(). As soon as I call Init() instead of CreateCommands() in my Task as seen below. ExecuteClick() will not be called when I press the Button.
public void Init()
{
((MainWindowViewModel)DataContext).CreateCommands();
}
--
Task.Run(() =>
{
mw.Init();
});
Since calling mw.Init() without the Task works, I suspected some problem with the WPF Dispatcher, so I tried using App.Current.Dispatcher.BeginInvoke(new Action(() =>mw.Init())); and Invoke, but that didn't change anything. I also tried to replicate this behavior when placing the Init() Mehtod in other UI elements, but calling it from another window like this would work again:
public Window1()
{
InitializeComponent();
MainWindow mw = new MainWindow();
MainWindowViewModel vm = new MainWindowViewModel();
mw.DataContext = vm;
Task.Run(() =>
{
Init(vm);
});
mw.ShowDialog();
}
public void Init(MainWindowViewModel vm)
{
vm.CreateCommands();
}
I also tried differences between Core and Framework, or saving my ViewModel in a Member Variable instead of using DataContext, without any notable difference.
What exactly happens, that blocks my commands from being created only when creating them in a thread via the view?
AsyncRelayCommandclass examples. The issue is old as world.