C# 从ViewModel调用异步方法
我有一个C# 从ViewModel调用异步方法,c#,xamarin,async-await,xamarin.forms,uwp,C#,Xamarin,Async Await,Xamarin.forms,Uwp,我有一个视图模型,它利用了。在此ViewModel中,我想访问。有了这个插件,我必须打电话。因为它使用async调用,所以我有一些计时问题 这是我的代码: public ICommand CameraCommand { get { return _cameraCommand ?? (_cameraCommand = new Command(async () => await ExecuteCameraCommand(), () => CanExecuteCameraComma
视图模型
,它利用了。在此ViewModel
中,我想访问。有了这个插件,我必须打电话。因为它使用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环境中测试此代码。您没有提供,尤其是没有显示命令
类的实现。所以我在这里假设它是您引用的Xamarin文章中描述的命令
类
视图模型异步初始化的基本策略如下:
private async Task InitMedia()
{
await CrossMedia.Current.Initialize();
this.initialized = true;
_cameraCommand.ChangeCanExecute();
}
Command.ChangeCanExecute()
方法引发CanExecuteChanged
事件,以便当CanExecute()
方法的结果不同时,可以通知绑定到该命令的控件。通过在初始化完成时调用此方法,可以解决即使在初始化完成后按钮仍处于禁用状态的问题
另一个注意事项是:我不会调用InitMedia()
方法,也不会从CanExecuteCameraCommand()
方法进行任何初始化。因为初始化是异步的,所以无论如何,在从该方法返回之前,您都无法成功地初始化,而且您已经从构造函数获得了对初始化的调用。ICommand.CanExecute()
实现应该非常简单,严格限制为检查事物的当前状态,并根据这些结果返回所需的bool
值
如果上述内容不能解决您的问题,请通过提供一个好的MCVE来改进问题,并更详细地解释出现了什么问题,您试图解决什么问题,以及您在解决问题时遇到的具体问题。您能分享MyViewModel的用法吗?它与我的XAML一样使用。是的,在初始化之前是否调用BindingContex?在xmal构造函数中是这样的吗?public LoginPage(){vm=new LoginPageViewModel();BindingContext=vm;InitializeComponent();}是的,我应该切换吗?尝试这样的操作:public LoginPage(){vm=new LoginPageViewModel();BindingContext=vm;InitializeComponent();vm.InitData();}将其公开,并从viewmodel的构造函数ogf中删除InitData。命令
实现了。我和你得出了同样的结论,我必须重新检查状态。再次调用视图模型的CanExecuteCameraCommand()
没有帮助,因为结果没有在任何地方使用。在ICommand
界面中,没有定义ChangeCanExecute()
方法。如果可能的话,我是否应该更改命令
类?或者我可以以某种方式触发CanExecuteChanged
事件吗?我认为我必须实现Xamarin文章中提到的命令
,而不是ICommand
。“该命令实现ICommand接口”——是的,但它是命令
类,以及该类(假设您正在使用)没有ChangeCanExecute()
方法。您只需确保\u cameraCommand
变量的类型为命令
,而不是ICommand
。你不需要实现任何东西;您正在使用的命令
类已经做到了这一点……只需确保不要通过将实例引用存储在ICommand
变量中来限制自己。是的,我认为这将是问题的解决方案。我会试试看,等我做完后给你打勾。