处理这两个依赖于另一个的异步方法的最佳方法是什么?
What is the best way to handle this two async methods that one dependent on the other?
我使用的是最新版本的 Prism Library。
我的列表页面视图模型 - ActivityListPageViewModel.cs 有类似下面的内容,基本上它是一个列表,当它 clicked/selected 然后将导航到详细信息页。
public ActivityModel SelectedItem
{
get => _selectedActivity;
set
{
SetProperty(ref _selectedActivity, value);
if (_selectedActivity != null)
ShowActivityDetails(_selectedActivity);
}
}
async void ShowActivityDetails(ActivityModel selectedActivity)
{
var navigationParams = new NavigationParameters();
navigationParams.Add("activity", selectedActivity);
await _navigationService.NavigateAsync("ActivityDetailPage", navigationParams);
}
在我的详情页面视图模型中 - ActivityDetailPageViewModel.cs
public class ActivityDetailPageViewModel : ViewModelBase, IActiveAware, INavigationAware
{
private readonly IActivityApiService _activityApiService;
private readonly ICategoryApiService _categoryApiService;
private readonly INavigationService _navigationService;
private readonly IPageDialogService _dialogService;
public DelegateCommand DeleteCommand { get; private set; }
public DelegateCommand SaveCommand { get; private set; }
private ActivityModel _activity;
public ActivityModel Activity
{
get { return this._activity; }
set
{
SetProperty(ref this._activity, value);
}
}
private ActivityModelValidator _activityValidator;
private bool _isActive;
public bool IsActive
{
get { return _isActive; }
set
{
_isActive = value;
SetProperty(ref _isActive, value, RaiseIsActiveChange);
}
}
private List<CategoryModel> _categoryList;
public List<CategoryModel> CategoryList
{
get => _categoryList;
set => SetProperty(ref _categoryList, value);
}
private CategoryModel _selectedCategory;
public event EventHandler IsActiveChanged;
public CategoryModel SelectedCategory
{
get => _selectedCategory;
set => SetProperty(ref _selectedCategory, value);
}
//public bool IsActive { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public ActivityDetailPageViewModel(CategoryApiService categoryApiService, ActivityApiService activityApiService, INavigationService navigationService, IPageDialogService dialogService) : base(navigationService)
{
_categoryApiService = categoryApiService;
_activityApiService = activityApiService;
_navigationService = navigationService;
_dialogService = dialogService;
_activityValidator = new ActivityModelValidator();
Title = "Activity";
DeleteCommand = new DelegateCommand(DeleteActivity);
SaveCommand = new DelegateCommand(SaveActivity);
}
protected virtual void RaiseIsActiveChange()
{
IsActiveChanged?.Invoke(this, EventArgs.Empty);
}
public override void OnNavigatedTo(INavigationParameters parameters)
{
var activity = parameters["activity"] as ActivityModel;
Activity = activity ?? new ActivityModel();
Task.Run(async () => { await FetchCategories(); }).Wait();
Task.Run(async () => { await FetchActivityDetail(); });
}
public async Task FetchActivityDetail()
{
if (Activity.Id > 0)
{
Activity = await _activityApiService.GetActivity(Activity.Id);
SelectedCategory = CategoryList.FirstOrDefault(x => x.Id == Activity.CategoryId);
}
}
public async Task FetchCategories()
{
CategoryResultModel categoryResult = await _categoryApiService.GetCategories();
CategoryList = categoryResult.Results;
}
async void SaveActivity()
{
Activity.CategoryId = SelectedCategory.Id;
Activity.CategoryName = SelectedCategory.Name;
var validationResults = _activityValidator.Validate(Activity);
if (validationResults.IsValid)
{
if (Activity.Id != 0)
{
bool isUserAccept = await _dialogService.DisplayAlertAsync("Activity", "Update the details", "OK", "Cancel");
if (isUserAccept)
{
var response = await _activityApiService.UpdateActivity(Activity.Id, Activity);
if (!response)
{
await _dialogService.DisplayAlertAsync("Activity", "Error.", "OK");
}
else
{
await _navigationService.NavigateAsync("NavigationPage/ActivityListPage");
}
}
}
else
{
bool isUserAccept = await _dialogService.DisplayAlertAsync("Activity", "Add a new details", "OK", "Cancel");
if (isUserAccept)
{
var response = await _activityApiService.AddActivity(Activity);
if (!response)
{
await _dialogService.DisplayAlertAsync("Activity", "Error.", "OK");
}
else
{
await _navigationService.NavigateAsync("NavigationPage/ActivityListPage");
}
}
}
}
else
{
await _dialogService.DisplayAlertAsync("Activity", validationResults.Errors[0].ErrorMessage, "OK");
}
}
async void DeleteActivity()
{
var alert = await _dialogService.DisplayAlertAsync("Activity", "Do you want to delete this item?", "Yes", "Cancel");
if (alert)
{
var response = await _activityApiService.DeleteActivity(Activity.Id);
if (!response)
{
await _dialogService.DisplayAlertAsync("Activity", "Error.", "OK");
}
else
{
await _navigationService.NavigateAsync("NavigationPage/ActivityListPage");
}
}
}
}
我按照建议将最初从 Constructor 中获取的两个数据(FetchCategories 和 FetchActivityDetail )移到了 OnNavigatedTo()
中。一切都很好 运行ning。但是我的问题是,因为 Fetch Categories 需要先 运行 然后完成 运行 FetchActivityDetail,下面的方法可以吗?我在某处读到,只要远离 Constructor,Wait 就可以以某种方式安全 运行。
Task.Run(async () => { await FetchCategories(); }).Wait();
Task.Run(async () => { await FetchActivityDetail(); });
有没有更好的方法?
谢谢
Task.Run(async () => { await FetchCategories(); await FetchActivityDetail(); });
最简单的解决方案是将 override 转换为 async,这样你就可以调用 async 方法如您通常所用。
优点是正确的 context 将传递给 async 方法,如果您 offload 与 Task.Run
public override async void OnNavigatedTo(INavigationParameters parameters)
{
try
{
var activity = parameters["activity"] as ActivityModel;
Activity = activity ?? new ActivityModel();
await FetchCategories();
await FetchActivityDetail();
}
catch(Exception ex)
{
// log or tell the user
}
}
注意 :因为这是一个异步无效,你需要小心你的异常,因为它们不会被观察到,所以最好抓住他们
我使用的是最新版本的 Prism Library。
我的列表页面视图模型 - ActivityListPageViewModel.cs 有类似下面的内容,基本上它是一个列表,当它 clicked/selected 然后将导航到详细信息页。
public ActivityModel SelectedItem
{
get => _selectedActivity;
set
{
SetProperty(ref _selectedActivity, value);
if (_selectedActivity != null)
ShowActivityDetails(_selectedActivity);
}
}
async void ShowActivityDetails(ActivityModel selectedActivity)
{
var navigationParams = new NavigationParameters();
navigationParams.Add("activity", selectedActivity);
await _navigationService.NavigateAsync("ActivityDetailPage", navigationParams);
}
在我的详情页面视图模型中 - ActivityDetailPageViewModel.cs
public class ActivityDetailPageViewModel : ViewModelBase, IActiveAware, INavigationAware
{
private readonly IActivityApiService _activityApiService;
private readonly ICategoryApiService _categoryApiService;
private readonly INavigationService _navigationService;
private readonly IPageDialogService _dialogService;
public DelegateCommand DeleteCommand { get; private set; }
public DelegateCommand SaveCommand { get; private set; }
private ActivityModel _activity;
public ActivityModel Activity
{
get { return this._activity; }
set
{
SetProperty(ref this._activity, value);
}
}
private ActivityModelValidator _activityValidator;
private bool _isActive;
public bool IsActive
{
get { return _isActive; }
set
{
_isActive = value;
SetProperty(ref _isActive, value, RaiseIsActiveChange);
}
}
private List<CategoryModel> _categoryList;
public List<CategoryModel> CategoryList
{
get => _categoryList;
set => SetProperty(ref _categoryList, value);
}
private CategoryModel _selectedCategory;
public event EventHandler IsActiveChanged;
public CategoryModel SelectedCategory
{
get => _selectedCategory;
set => SetProperty(ref _selectedCategory, value);
}
//public bool IsActive { get => throw new NotImplementedException(); set => throw new NotImplementedException(); }
public ActivityDetailPageViewModel(CategoryApiService categoryApiService, ActivityApiService activityApiService, INavigationService navigationService, IPageDialogService dialogService) : base(navigationService)
{
_categoryApiService = categoryApiService;
_activityApiService = activityApiService;
_navigationService = navigationService;
_dialogService = dialogService;
_activityValidator = new ActivityModelValidator();
Title = "Activity";
DeleteCommand = new DelegateCommand(DeleteActivity);
SaveCommand = new DelegateCommand(SaveActivity);
}
protected virtual void RaiseIsActiveChange()
{
IsActiveChanged?.Invoke(this, EventArgs.Empty);
}
public override void OnNavigatedTo(INavigationParameters parameters)
{
var activity = parameters["activity"] as ActivityModel;
Activity = activity ?? new ActivityModel();
Task.Run(async () => { await FetchCategories(); }).Wait();
Task.Run(async () => { await FetchActivityDetail(); });
}
public async Task FetchActivityDetail()
{
if (Activity.Id > 0)
{
Activity = await _activityApiService.GetActivity(Activity.Id);
SelectedCategory = CategoryList.FirstOrDefault(x => x.Id == Activity.CategoryId);
}
}
public async Task FetchCategories()
{
CategoryResultModel categoryResult = await _categoryApiService.GetCategories();
CategoryList = categoryResult.Results;
}
async void SaveActivity()
{
Activity.CategoryId = SelectedCategory.Id;
Activity.CategoryName = SelectedCategory.Name;
var validationResults = _activityValidator.Validate(Activity);
if (validationResults.IsValid)
{
if (Activity.Id != 0)
{
bool isUserAccept = await _dialogService.DisplayAlertAsync("Activity", "Update the details", "OK", "Cancel");
if (isUserAccept)
{
var response = await _activityApiService.UpdateActivity(Activity.Id, Activity);
if (!response)
{
await _dialogService.DisplayAlertAsync("Activity", "Error.", "OK");
}
else
{
await _navigationService.NavigateAsync("NavigationPage/ActivityListPage");
}
}
}
else
{
bool isUserAccept = await _dialogService.DisplayAlertAsync("Activity", "Add a new details", "OK", "Cancel");
if (isUserAccept)
{
var response = await _activityApiService.AddActivity(Activity);
if (!response)
{
await _dialogService.DisplayAlertAsync("Activity", "Error.", "OK");
}
else
{
await _navigationService.NavigateAsync("NavigationPage/ActivityListPage");
}
}
}
}
else
{
await _dialogService.DisplayAlertAsync("Activity", validationResults.Errors[0].ErrorMessage, "OK");
}
}
async void DeleteActivity()
{
var alert = await _dialogService.DisplayAlertAsync("Activity", "Do you want to delete this item?", "Yes", "Cancel");
if (alert)
{
var response = await _activityApiService.DeleteActivity(Activity.Id);
if (!response)
{
await _dialogService.DisplayAlertAsync("Activity", "Error.", "OK");
}
else
{
await _navigationService.NavigateAsync("NavigationPage/ActivityListPage");
}
}
}
}
我按照建议将最初从 Constructor 中获取的两个数据(FetchCategories 和 FetchActivityDetail )移到了 OnNavigatedTo()
中。一切都很好 运行ning。但是我的问题是,因为 Fetch Categories 需要先 运行 然后完成 运行 FetchActivityDetail,下面的方法可以吗?我在某处读到,只要远离 Constructor,Wait 就可以以某种方式安全 运行。
Task.Run(async () => { await FetchCategories(); }).Wait();
Task.Run(async () => { await FetchActivityDetail(); });
有没有更好的方法?
谢谢
Task.Run(async () => { await FetchCategories(); await FetchActivityDetail(); });
最简单的解决方案是将 override 转换为 async,这样你就可以调用 async 方法如您通常所用。
优点是正确的 context 将传递给 async 方法,如果您 offload 与 Task.Run
public override async void OnNavigatedTo(INavigationParameters parameters)
{
try
{
var activity = parameters["activity"] as ActivityModel;
Activity = activity ?? new ActivityModel();
await FetchCategories();
await FetchActivityDetail();
}
catch(Exception ex)
{
// log or tell the user
}
}
注意 :因为这是一个异步无效,你需要小心你的异常,因为它们不会被观察到,所以最好抓住他们