【问题标题】:What is the best way to handle this two async methods that one dependent on the other?处理这两个依赖于另一个的异步方法的最佳方法是什么?
【发布时间】:2019-11-20 07:31:04
【问题描述】:

我正在使用最新版本的 Prism Library。

我的列表页面视图模型 - ActivityListPageViewModel.cs 在下面有类似的东西,基本上它是一个列表,当它单击/选择时,它将导航到详细信息页面。

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()。一切运行良好。但是我的问题是,由于 Fetch Categories 需要先运行并完成然后运行 ​​FetchActivityDetail,以下方法可以吗?我在某处读到,只要远离构造函数,Wait 就可以安全地以某种方式运行。

Task.Run(async () => { await FetchCategories(); }).Wait();
Task.Run(async () => { await FetchActivityDetail(); });

有没有更好的方法?

谢谢

【问题讨论】:

  • Task.Run(...).Wait(); 完全没有意义,你想让它在后台运行(TaskRun)还是不运行(Wait)?

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


【解决方案1】:

最简单的解决方案是将 override 转换为 async,这样您就可以像往常一样调用 async 方法。

优点是正确的 context 将被传递给 async 方法,如果您使用 @987654321 offload 就不会发生这种情况@

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
     }
}

注意:因为这是一个异步 void,你需要小心你的异常,因为它们不会被观察到,所以最好抓住它们

【讨论】:

  • 我在“等待”运算符只能在异步方法中使用此错误。考虑使用 'async' 修饰符标记此方法并将其返回类型更改为 'Task'
  • @dcpartners public override async void OnNavigatedTo 注意方法上的 async 关键字
  • 关于小心异常,你指的是public override async void OnNavigatedTo(INavigationParameters parameters)方法吗?
  • @dcpartners 是的,最好放一个 try catch 来封装该方法的全部内容。并记录结果,或向用户展示等。
【解决方案2】:
Task.Run(async () => { await FetchCategories(); await FetchActivityDetail();  });

【讨论】:

    猜你喜欢
    • 2013-10-13
    • 2012-09-02
    • 2020-09-27
    • 2017-09-30
    • 2010-09-21
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    • 1970-01-01
    相关资源
    最近更新 更多