从ViewModel调用异步方法

时间:2016-11-08 16:30:02

标签: c# xamarin async-await xamarin.forms uwp

我有一个ViewModel,它使用Commanding。在此ViewModel我想访问MediaPlugin 。使用此插件,我必须致电Initialize()。因为它使用async次调用,所以我有一些时间问题。

这是我的代码:

public ICommand CameraCommand
{
    get { return _cameraCommand ?? (_cameraCommand = new Command(async () => await ExecuteCameraCommand(), () => CanExecuteCameraCommand())); }
}

public bool CanExecuteCameraCommand()
{
    // Check if initialized before calling properties
    if (!this.initialized)
        InitMedia();

    if (!this.initialized || !CrossMedia.Current.IsCameraAvailable || !CrossMedia.Current.IsTakePhotoSupported)
    {
        return false;
    }
    return true;
}

public async Task ExecuteCameraCommand()
{
    // Assure that it is initialized before calling method
    var file = await CrossMedia.Current.TakePhotoAsync(new StoreCameraMediaOptions {});
    // ...
}

private void InitMedia()
{
    CrossMedia.Current.Initialize();
    this.initialized = true;
}

使用此代码,应用程序崩溃

  

在调用任何属性之前,您必须调用Initialize()   在Plugin.Media.MediaImplementation.get_IsCameraAvailable()

当我在构造函数中开始初始化时,就像使用此代码一样

public MyViewModel()
{
    InitData();
}

private async Task InitData()
{
    // ...
    await InitMedia();
}

private async Task InitMedia()
{
    await CrossMedia.Current.Initialize();
    this.initialized = true;
}

public bool CanExecuteCameraCommand()
{
    // Check if initialized before calling properties
    if (!this.initialized)
        return false;
    // ...
}
在初始化完成之前调用

CanExecuteCameraCommand()。因此,返回false并禁用UI中的按钮。

我正在Windows 10移动设备(Windows 10 Universal)上的Xamarin.Forms环境中测试此代码。

1 个答案:

答案 0 :(得分:2)

您尚未提供Minimal, Complete, and Verifiable code example,特别是您没有展示Command课程的实施情况。所以我在这里假设它是您引用的Xamarin文章中描述的Command类。

视图模型的异步初始化的基本策略是:

  1. 禁用任何依赖于初始化结果的命令,清除依赖于初始化结果的任何属性(或设置为适当的默认值)。
  2. 开始异步初始化。
  3. 使用某种延续机制(即不阻塞线程)等待异步初始化完成。
  4. 初始化完成后,重新启用以前禁用的命令并更新任何相关属性。
  5. 根据您发布的代码,在我看来,缺少的主要内容是第4步。即你没有做任何事情来重新启用以前禁用的命令,即使你有一个方便的地方:

    private async Task InitMedia()
    {
        await CrossMedia.Current.Initialize();
        this.initialized = true;
        _cameraCommand.ChangeCanExecute();
    }
    

    Command.ChangeCanExecute()方法引发CanExecuteChanged事件,以便在CanExecute()方法的结果不同时,可以通知绑定到命令的控件。通过在初始化完成时调用此方法,这应解决即使在初始化完成后按钮仍保持禁用的问题。

    另外需要注意:我会 调用InitMedia()方法,或者根据CanExecuteCameraCommand()方法进行任何初始化。因为初始化是异步的,所以不管你是否能够在从该方法返回之前成功初始化,并且你已经从构造函数调用了初始化。 ICommand.CanExecute()实现应该非常简单,并且严格限于检查事物的当前状态并根据这些结果返回所需的bool值。

    如果上述问题没有解决您的问题,请通过提供良好的MCVE来改进问题,并更详细地解释出现问题的原因,您尝试修复的问题以及具体问题。进行。

相关问题