C# 在MVVM中初始化类后执行异步方法

C# 在MVVM中初始化类后执行异步方法,c#,wpf,asynchronous,mvvm,C#,Wpf,Asynchronous,Mvvm,我希望在应用程序初始化并出现主窗口后执行这些代码行: if (System.IO.File.Exists("token")) { string[] startupStrings = Environment.GetCommandLineArgs(); await _myOneDrive.SilentLogIn(); IsActive = true; if (startupStrings.Length > 1 && startupStrings

我希望在应用程序初始化并出现主窗口后执行这些代码行:

if (System.IO.File.Exists("token"))
{

    string[] startupStrings = Environment.GetCommandLineArgs();
    await _myOneDrive.SilentLogIn();
    IsActive = true;
    if (startupStrings.Length > 1 && startupStrings[1] == "/a")
    {
        IsWorking = true;
        IsActive = false;
        await _myOneDrive.EjectSynchroProcedure(false);
        IsActive = true;
        IsWorking = false;
        Application.Current.Shutdown();
    }
}
不幸的是,我不能这样做,因为我不能在MVVM模型构造函数中使用
await
操作符。注册
Loaded
事件破坏了MVVM的整个理念。我读过一篇文章,一般不使用
async void
,只在事件处理程序的逻辑等价物中使用。因此,我的异步命令如下所示:

async void SilentLogin(object parameter)
{
    await _myOneDrive.SilentLogin();
    IsActive = true;
}
然后在构造函数中初始化它们,并将命令绑定到XAML代码中的按钮

public MainWindowViewModel()
{
    _myOneDrive = new MyOneDriveClient(PathPcDirectory, PathOneDriveDirectory, this);
    LoginCommand = new RelayCommand(Login);
    SilentLoginCommand = new RelayCommand(SilentLogin);
    Console = "Program started";
}

它工作得很好,但我仍然无法实现在初始化后运行代码的目标。我不能等待我的
async void Login(对象参数)
命令,因为它是
void
而不是
任务
。此外,我无法将其更改为
任务
,因为它对
RelayCommand
无效。因此,我在这个循环中,真的会使用一些提示、技巧或只是指出我的错误。

当我遇到类似问题并发现一个非常简单的AsyncRelayCommand实现时

public class AsyncRelayCommand : RelayCommand
{
    private readonly Func<Task> _asyncExecute;

    public AsyncRelayCommand(Func<Task> asyncExecute)
        : base(() => asyncExecute())
    {
        _asyncExecute = asyncExecute;
    }

    public AsyncRelayCommand(Func<Task> asyncExecute, Action execute)
        : base(execute)
    {
        _asyncExecute = asyncExecute;
    }

    public Task ExecuteAsync()
    {
        return _asyncExecute();
    }

    public override void Execute(object parameter)
    {
        _asyncExecute();
    }
}
公共类AsyncRelayCommand:RelayCommand
{
私有只读函数异步执行;
公共AsyncRelayCommand(Func asyncExecute)
:base(()=>asyncExecute())
{
_asyncExecute=asyncExecute;
}
公共AsyncRelayCommand(Func asyncExecute,Action execute)
:base(执行)
{
_asyncExecute=asyncExecute;
}
公共任务ExecuteAsync()
{
返回_asyncExecute();
}
公共覆盖无效执行(对象参数)
{
_异步执行();
}
}
然后只需修改方法以返回任务,并用新创建的AsyncRelayCommand替换RelayCommand的用法。对我来说很好


请注意,带有参数的用法可能还不起作用,因此您需要对此进行一些额外的实现。对我来说,这是没有必要的。但是您应该了解基本的想法。

我认为从加载的视图事件调用ViewModel的
Initialize
方法没有问题。我不认为这违反了MVVM。我同意@Euphoric。该视图是关于VM的。查看绑定到它并使用它。MVVM的目标是让VM不必担心其属性在视图中如何表示,但这并不意味着视图不应该知道如何使用VM。谢谢。它显然工作得很好。我把它带到我的壁炉前,不使用代码隐藏,但它似乎是更好的解决方案。我尝试过使用
Dispatcher
,但开始得很早。在UI任务中使用codebehind绝对没有错。不要落入那个陷阱。我会建议使用Dispatcher,但我会告诉您指定一个非常低的
DispatcherPriority
,以便在数据绑定完成后初始化视图模型。您是对的。它工作得很好。然而,它也可以使用简单的
RelayCommand
async void
。我的问题是如何在启动时弹出该命令或等待函数。我决定使用
Loaded
事件。