简体   繁体   English

如何等待命令的任务?

[英]How to await a task from a command?

I am trying to wait for the end of a task.我正在尝试等待任务结束。 This task loads a bunch of things from the server and usually takes about 2 to 3 seconds.此任务从服务器加载一堆东西,通常需要大约 2 到 3 秒。 This task is started by the command LoadItemsCommand.此任务由命令 LoadItemsCommand 启动。 Once the task is over, it should check if anything has been loaded, and if any of the loaded items already contain values.任务结束后,它应检查是否已加载任何内容,以及是否有任何已加载的项目已包含值。 If yes, it should remove a button from the Toolbar.如果是,它应该从工具栏中删除一个按钮。

But it doesn't wait.但它不会等待。 The command call and specifically ask to await the task, but on the main page, things procede without waiting for the end of the task.命令调用并特别要求等待任务,但在主页上,事情在不等待任务结束的情况下继续进行。 i tried to put a loop with 30 second wait time to wait for the command to work, but nothing.我试图用 30 秒的等待时间循环等待命令工作,但没有。

Here is the command in the viewmodel:这是视图模型中的命令:

LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());

Here is the LoadItems Function in the ViewModel这是 ViewModel 中的 LoadItems Function

async Task ExecuteLoadItemsCommand()
{
    if (IsBusy)
        return;
    IsBusy = true;

    List<string> stockIds = new List<string>();
    foreach (var orderline in this._order)
    {
        stockIds.Add(orderline.StockId);
    }
    string[] array = new string[stockIds.Count];
    stockIds.CopyTo(array, 0);
    this._products = await Common.GetProducts(new ProductSearchFilter { StockId = array });

    _scanStart = Common.Now;
    Items.Clear();

    bool already_scanned = false; // Todo trouver un meilleur non car pas tres explicite

    foreach (PickingOrderLineToHandle orderLine in _order)
    {
        if (orderLine.ScannedQuantity < orderLine.Quantity)
        {
            if ((bool)orderLine.WasSentToEnd && !already_scanned)
            {
                Items.Add(new ListItem() { Name = " ----- ", Id = "-1" });
                already_scanned = true;
            }

            Product product = null;
            foreach (var prod in _products)
            {
                if (prod.StockId == orderLine.StockId)
                {
                    product = prod;
                    break;
                }
            }
            Items.Add(new ListItem() { Name = $"{(orderLine.Quantity - orderLine.ScannedQuantity).ToString()} / {orderLine.Quantity}\t + {orderLine.Table_bin.LabelAddress} {product.ProductName} {orderLine.stock.Platform}", Id = orderLine.StockId });
        }
    }

    IsBusy = false;
}

And here is the call in the page:这是页面中的调用:

protected override void OnAppearing()
{
    base.OnAppearing();

    viewModel.LoadItemsCommand.Execute(null);

    int loop = 0;
    while (viewModel.IsBusy && loop < 60)
    {
        System.Threading.Thread.Sleep(500);
        loop++;
    };

    if (loop == 60)
    {
        DisplayAlert("Erreur", "Une erreur est survenue lors du chargment. Veuillez réessayer.", "Ok");
        Navigation.PopAsync();
    }

    var cantCancel = viewModel.Items.Any(i => i.BookedQuantity > 0);

    if (Common.IsTeamLeader)
        cantCancel = false;

    if (cantCancel)
    {
        var cancelButton = this.ToolbarItems.Where(b => b.Text == "Annuler").First();
        this.ToolbarItems.Remove(cancelButton);
    }
}

Problem问题

The following statement seems like a blocking call, but actually, since the method that is called by the Command is an asynchronous anonymous function, it will just execute in a fire and forget fashion and will not be awaited:下面的语句看起来像是一个阻塞调用,但实际上,由于Command调用的方法是一个异步匿名function ,它只会以一种即刻执行并不会被等待的方式执行:

viewModel.LoadItemsCommand.Execute(null);

That's because of how the Command is defined:这是因为 Command 的定义方式:

LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());

A Command like this always executes synchronously.像这样的Command总是同步执行。 However, when calling an async void method from within a synchronous context, it will just begin execution, but won't await the method (hence fire and forget ).但是,当从同步上下文中调用async void方法时,它只会开始执行,但不会await该方法(因此fire and forget )。

Solution解决方案

Now, the way you're using the Command is unusual.现在,您使用Command的方式很不寻常。 Normally, you would bind to the Command from a UI control or you would just trigger it's execution.通常,您会从 UI 控件绑定到Command ,或者只是触发它的执行。 You are expecting it to finish before the rest of the code is executed, which isn't the case as I've explained above.您期望它在执行代码的 rest 之前完成,但正如我上面所解释的那样,情况并非如此。

Instead of executing the Command like that, you could instead do the following:您可以执行以下操作,而不是像那样执行命令:

  1. Make sure ExecuteLoadItemsCommand() is returning a Task确保ExecuteLoadItemsCommand()正在返回一个Task
  2. Change the visibility of ExecuteLoadItemsCommand() to publicExecuteLoadItemsCommand()的可见性更改为公开
  3. Change the name to ExecuteLoadItemsAsync() which is a common notation for methods that return asynchronous Tasks将名称更改为ExecuteLoadItemsAsync() ,这是返回异步任务的方法的常用符号

Your new method signature should look something like this:您的新方法签名应如下所示:

public async Task ExecuteLoadItemsAsync()
{
    //...
}

Then, in your page's code-behind, you could change the OnAppearing() method override to run asynchronously by adding the async keyword to the signature and then awaiting the ExecuteLoadItemsAsync() method:然后,在页面的代码隐藏中,您可以通过将async关键字添加到签名然后等待ExecuteLoadItemsAsync()方法,将OnAppearing()方法覆盖更改为异步运行:

protected override async void OnAppearing()
{
    base.OnAppearing();

    await viewModel.ExecuteLoadItemsAsync();

    //...
}

This way, you're executing and awaiting the method directly.这样,您就可以直接执行和等待该方法。 The Command can still be used for any UI elements to bind to, such as buttons. Command仍然可以用于任何要绑定到的 UI 元素,例如按钮。

Optional improvement可选改进

In your ViewModel, you could use an AsyncRelayCommand instead of Command like this:在您的 ViewModel 中,您可以使用AsyncRelayCommand而不是Command ,如下所示:

private AsyncRelayCommand _loadItemsCommand;
public AsyncRelayCommand LoadItemsCommand => _loadItemsCommand ??= new AsyncRelayCommand(ExecuteLoadItemsAsync);

However, this doesn't change the fact that you shouldn't execute the Command in your page's code behind the way you've been attempting.但是,这不会改变您不应该按照您一直尝试的方式在页面代码中执行命令的事实。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM