【发布时间】:2020-11-13 03:37:46
【问题描述】:
我目前正在开发一个登录窗口,它应该负责建立与服务器的连接、验证用户凭据,然后打开一个 MVVM 'MainWindow'。我想稍微加快 MainWindow 的打开过程,这就是为什么我试图将其 ViewModel 的初始化转移到自己的Task 中。这不知何故破坏了我的命令,我不明白为什么,所以我创建了一个最小可重现示例来解释我的问题。
ViewModel 看起来像这样:
public class MainWindowViewModel
{
public MainWindowViewModel()
{
}
public ICommand ClickCommand { get; set; }
public void CreateCommands()
{
ClickCommand = new RelayCommand(ExecuteClick);
}
public void ExecuteClick()
{
}
View 只是一个默认窗口,带有一个带有命令绑定的按钮:Command="{Binding ClickCommand}"
我创建视图和视图模型并从任务中调用CreateCommands,这很有效。
MainWindow mw = new MainWindow();
MainWindowViewModel vm = new MainWindowViewModel();
mw.DataContext = vm;
Task.Run(() =>
{
vm.CreateCommands();
});
mw.ShowDialog();
现在我在我的视图中创建一个新方法Init() 并让它调用CreateCommands()。只要我在我的任务中调用Init() 而不是CreateCommands(),如下所示。按下按钮时不会调用ExecuteClick()。
public void Init()
{
((MainWindowViewModel)DataContext).CreateCommands();
}
--
Task.Run(() =>
{
mw.Init();
});
由于在没有任务的情况下调用mw.Init(),我怀疑WPF 调度程序有问题,所以我尝试使用App.Current.Dispatcher.BeginInvoke(new Action(() =>mw.Init())); 和Invoke,但这并没有改变任何东西。在将 Init() Mehtod 放置在其他 UI 元素中时,我也尝试复制此行为,但从另一个窗口调用它会再次起作用:
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();
}
我还尝试了 Core 和 Framework 之间的差异,或者将我的 ViewModel 保存在成员变量中而不是使用 DataContext,没有任何显着差异。
到底发生了什么,只有在通过视图在线程中创建命令时才阻止创建我的命令?
【问题讨论】:
-
ICommand 属性的异步初始化不会使命令异步。你可能想看看这个:stackoverflow.com/q/54232156/1136211
-
Showdialog 被阻止,所以我想知道它是否会阻止您的任务。您也没有实现 inpc 并在您的命令属性设置时通知,以便永远不会拾取该命令。
-
Asynchronous Programming。有关异步命令实现的示例,请查找
AsyncRelayCommand类示例。这个问题与世界一样古老。
标签: c# wpf multithreading mvvm