当我在短时间内几次单击按钮时,每次都会调用该方法,并且我的应用程序崩溃(当代码尝试导航到另一个页面时)。仅在Xamarin.Android(iOS处理双击)中出现此问题
public bool IsBusy { get; set; }
private DelegateCommand<string> _eventDetailsCommand;
public DelegateCommand<string> EventDetailsCommand => _eventDetailsCommand ?? (_eventDetailsCommand = new DelegateCommand<string>(EventDetails, (x) => !IsBusy));
private void EventDetails(string obj)
{
IsBusy = true;
await _navigationService.NavigateAsync("AnotherPage");
IsBusy = false;
}
Xamarin.Android
棱镜:7.1.0.172(上)
PropertyChanged.Fody(2.2.6):
答案 0 :(得分:0)
private void EventDetails(string obj) { IsBusy = true; .... IsBusy = false; }
这会在整个事件处理程序执行期间阻塞UI线程,因此IsBusy = true;
和IsBusy = false;
都不会对ui产生任何可观察的影响。
这是async
的教科书示例。
您应该这样写:
private async void EventDetails(string obj)
{
IsBusy = true;
await ....;
IsBusy = false;
}
如果....
刚好不能使用,请将其包装在Task.Run
中:
private async void EventDetails(string obj)
{
IsBusy = true;
await Task.Run( () => .... );
IsBusy = false;
}
答案 1 :(得分:0)
请尝试
_deviceService.BeginInvokeOnMainThread(() =>
{
IsBusy = true;
});
//await ... long running process.
在上面的代码片段中,_deviceService的类型为IDeviceService,它是通过以下构造函数注入的:
private IDeviceService _deviceService;
/// <summary>
/// Class constructor
/// </summary>
/// <param name="deviceService"></param>
public MyPageViewModel(IDeviceService deviceService) {
_deviceService = deviceService;
}
答案 2 :(得分:0)
仅设置IsBusy不起作用,因为IsBusy更改时命令不会得到通知,UI也不通知。您必须使用RaiseCanExecuteChanged通知所有人。更好的方法是在创建DelegateCommand(Fluent API,但注意只能观察到一个属性)后仅使用ObservesCanExecute。它会为您解决这个问题,并将自动调用RaiseCanExecuteChanged。
以下是我通常如何处理的示例:
public MyViewModel(): ViewModelBase
{
private readonly INavigationService _navigationService;
public bool IsBusy { get; set; }
public ICommand ShowEventDetailsCommand { get; private set; }
public MyViewModel(INavigationService navService)
{
_navigationService = navService;
ShowEventDetailsCommand = new DelegateCommand<string>(async(obj) => await ExecuteShowEventDetailsCommand(obj)).ObservesCanExecute(() => !IsBusy);
}
public async Task ExecuteShowEventDetailsCommand(obj)
{
IsBusy = true; // Note this is not thread safe, just for demonstration
try
{
await _navigationService.NavigateAsync(...);
}
finally
{
IsBusy = false;
}
}
}
这通常是我处理此问题的方式。但是请注意,对IsBusy的访问不是线程安全的,因此您应该使用这样的东西。我有一个带有.TryLock,.Unlock和.IsLocked的LockActivityHandler。
if(LockActivityHandler.TryLock())
{
try
{
//DoStuff
}
finally
{
LockActivityHandler.Unlock();
}
}
IsLocked可以绑定到UI元素的Enabled属性以禁用它们。即使未禁用它们并且正在执行其他操作,由于TryLock()=> false
,新操作也不会执行PS:这也记录在文档中,带有更多示例,因此您可以在这里查看:https://prismlibrary.github.io/docs/commanding.html