我有一个ViewModel
,它使用Commanding
。在此 ViewModel
中,我想访问 MediaPlugin
。有了这个插件我必须打电话Initialize()
。因为它使用异步
调用,所以我遇到了一些计时问题。
这是我的代码:
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;
}
使用此代码,应用程序崩溃
You must call Initialize() before calling any properties.
at 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 通用)上的 Xamarin.Forms 环境中测试此代码。
最佳答案
您尚未提供Minimal, Complete, and Verifiable code example ,特别是您还没有显示 Command
类的实现。因此,我在这里假设它是您引用的 Xamarin 文章中描述的 Command
类。
View 模型异步初始化的基本策略是这样的:
- 禁用任何依赖于初始化结果的命令,清除依赖于初始化结果的任何属性(或设置为适当的默认值)。
- 开始异步初始化。
- 使用某种延续机制(即不阻塞线程)来等待异步初始化完成。
- 初始化完成后,重新启用之前禁用的命令并更新所有相关属性。
根据您发布的代码,在我看来,缺少的主要内容是步骤 #4。 IE。即使您有一个方便的地方可以这样做,您也没有执行任何操作来重新启用以前禁用的命令:
private async Task InitMedia()
{
await CrossMedia.Current.Initialize();
this.initialized = true;
_cameraCommand.ChangeCanExecute();
}
Command.ChangeCanExecute()
方法引发 CanExecuteChanged
事件,以便当 CanExecute() 的结果出现时,可以通知绑定(bind)到该命令的控件
方法会有所不同。通过在初始化完成时调用此方法,应该可以解决初始化完成后按钮仍然处于禁用状态的问题。
一个附加说明:我不会从CanExecuteCameraCommand()
调用InitMedia()
方法,或者根本不进行任何初始化方法。因为初始化是异步的,所以在从该方法返回之前您不可能成功初始化,并且您已经从构造函数调用了初始化。 ICommand.CanExecute()
实现应该非常简单,并且严格限于检查事物的当前状态并根据这些结果返回所需的 bool
值。
如果上述内容没有解决您的问题,请通过提供良好的 MCVE 来改进问题,并更准确地详细解释出现的问题、您尝试解决的问题以及您具体遇到的问题出来。
关于c# - 从 ViewModel 调用异步方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40491974/