DelegateCommand
是一种在 WPF(Windows Presentation Foundation)应用程序中常用的命令模式实现,它允许将方法作为命令绑定到 UI 元素上。当涉及到异步操作时,直接在 DelegateCommand
的执行方法中使用 Task.Run
可能会导致 UI 锁定,因为 Task.Run
会在一个新的线程上执行任务,而 WPF 的 UI 线程是单线程的,任何长时间运行的任务都会阻塞 UI 线程,导致应用程序无响应。
async
和 await
关键字在后台线程上执行,适用于耗时操作。问题: 使用 Task.Run
在 DelegateCommand
中执行异步操作时,UI 可能会锁定。
原因: Task.Run
会将任务放到线程池中执行,但 WPF 的 UI 操作必须在 UI 线程上执行。如果异步操作完成后需要更新 UI,而这个更新操作没有回到 UI 线程上执行,就会导致异常或 UI 锁定。
使用 async
和 await
关键字,并确保所有 UI 更新操作都在 UI 线程上执行。可以通过 Dispatcher.Invoke
或 Dispatcher.BeginInvoke
方法来实现。
public class RelayCommandAsync : ICommand
{
private readonly Func<Task> _execute;
private readonly Func<bool> _canExecute;
public RelayCommandAsync(Func<Task> execute, Func<bool> canExecute = null)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute();
}
public async void Execute(object parameter)
{
await _execute();
}
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
}
// Usage in ViewModel
public RelayCommandAsync MyAsyncCommand { get; }
public MyViewModel()
{
MyAsyncCommand = new RelayCommandAsync(async () =>
{
// Perform long-running task here
await Task.Delay(1000); // Simulate work
// Update UI after task completion
Application.Current.Dispatcher.Invoke(() =>
{
// UI update code here
});
});
}
在这个示例中,RelayCommandAsync
类实现了 ICommand
接口,并允许异步执行命令。在 Execute
方法中,使用 await
关键字等待异步操作完成,然后通过 Dispatcher.Invoke
确保 UI 更新操作在 UI 线程上执行。
这种方法可以有效地避免 UI 锁定问题,同时保持应用程序的响应性。
领取专属 10元无门槛券
手把手带您无忧上云