异步方法同时被调用2次

时间:2019-05-23 07:07:04

标签: c# wpf mvvm task

这是我的关注。我有两个有时必须同时触发的datePickers(我选择了一个代理,得到了它的开始日期和结束日期)。

我有一个方法可以根据日期检索计划,问题是它需要同时使用开始日期+结束日期+正常触发器(当我选择座席时,会显示其默认计划。 ) 因此,结果可以同时提供给我一些信息(我收到一条错误消息“无计划” +一项落后的计划,这毫无意义)

这是代码:

        <DatePicker Grid.Column="1" Name="DatePickerStart"
                            Grid.Row="5"
                            Margin="40,5"
                            Height="25"
                            DisplayDateEnd="{Binding DateEnd}"
                            SelectedDate="{Binding DateStart}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectedDateChanged">
                <i:InvokeCommandAction Command="{Binding LoadMatrice}" CommandParameter="{Binding SelectedDate, RelativeSource={RelativeSource AncestorType={x:Type DatePicker}}}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </DatePicker>
    <TextBlock Grid.Row="4"
                            Grid.Column="2" 
                            HorizontalAlignment="Center"
                            VerticalAlignment="Center"
                            FontSize="16"
                            Text="Date Fin:"/>
    <DatePicker Grid.Column="2" Name="DatePickerEnd"
                            Grid.Row="5"
                            Margin="40,5"
                            Height="25"
                            DisplayDateStart="{Binding DateStart}"
                            SelectedDate="{Binding DateEnd}">
        <i:Interaction.Triggers>
            <i:EventTrigger EventName="SelectedDateChanged">
                <i:InvokeCommandAction Command="{Binding LoadMatrice}" CommandParameter="{Binding SelectedDate, RelativeSource={RelativeSource AncestorType={x:Type DatePicker}}}"/>
            </i:EventTrigger>
        </i:Interaction.Triggers>
    </DatePicker>

VM:

        private DateTime _DateDebut;
    public DateTime DateDebut
    {
        get
        {
            return _DateDebut;
        }
        set
        {
            if (value != _DateDebut)
            {
                _DateDebut = value;
                RaisePropertyChanged(nameof(DateDebut));
            }
        }
    }

    private DateTime _DateFin;
    public DateTime DateFin
    {
        get
        {
            return _DateFin;
        }
        set
        {
            if (value != _DateFin)
            {
                _DateFin = value;
                RaisePropertyChanged(nameof(DateFin));
            }
        }
    }

当我在组合框中选择某些内容时:

        private string _SelectedResultList;
    public string SelectedResultList
    {
        get
        {
            return _SelectedResultList;
        }
        set
        {
            if (value != _SelectedResultList)
            {
                _SelectedResultList = value;

                //GetIdSelectedResultList();
                foreach (var periode in PeriodesModulation)
                {

                    if (value == valueILookingFor)
                    {
                        DateStart = periode.Start;
                        DateEnd = periode.End;
                    }
                }
                RaisePropertyChanged(nameof(SelectedResultList));
            }
        }
    }

触发的方法:

            LoadMatrice = new RelayCommand(async () =>
        {
            await GetParametresMatrice();
        });

和:

        public async Task GetParametresMatrice()
    {
        ErrorMatrice = null;

        if (_SelectedChoiceList != null) // important pour ne pas rechercher avec les dates.today du reset avant qu'on ai fait la demande
        {
            GetMatricule(matriculeSelectedAgent);
            Planning = new ObservableCollection<Planning>(await _dataService.GetPlanning(matriculeSelectedAgent, _dataService.ParamGlobaux.IDEtablissement, DateStart, DateEnd));
            GetIdMatrice(Planning);
            Matrice = new ObservableCollection<Matrix>(await _dataService.GetMatrice(idMatrice));
        }
    }

我计算找到的计划的数量,然后:

        private void GetIdMatrice(ObservableCollection<Planning> planning)
    {
        idMatrice = null;

        if (planning.Count > 0)
        {
            if (planning.Any(p => p.IDMatrice == null))
            {
                ErrorMatrice = $"Pas de matrice trouvées, modification impossible";
            }
            else if (planning.GroupBy(p => p.IDMatrice).Count() > 1)
            {
                ErrorMatrice = $"Deux matrices différentes trouvées, modification impossible";
            }
            else
            {
                idMatrice = planning.First().IDMatrice;
            }
        }
        else
        {
            ErrorMatrice = $"Pas de planning trouvé sur cette période.";
        }
    }

后者,GetParametresMatrice(),重复了几次,这是正常的,但同时又是有问题的。我希望循环一个接一个地完成。

第一次“加载”通过后,一切正常。如果我更改开始日期或结束日期,则时间表将进行调整。实际上,只有当我选择一个计划并且两个日期都已加载时。

编辑:在布局加载期间没有问题,因为“ if(_SelectedChoiceList!= null)”行。 这是我的组合框,非常完美。 问题是当我在组合框中选择一个代理并且StartDate / EndDate同时更改时。

编辑2:

end

当我显示结果时,我有一个时间表+错误消息。通常这是不可能的,Planning.count不能为> 1 AND <1

有什么提示吗?

谢谢。

2 个答案:

答案 0 :(得分:1)

您的主要问题似乎是您的ICommand实现(RelayCommand)不同步或无法等待。如果是这样,您本可以等待LoadMatrice命令。

您将找到一个异步ICommand实现here的示例。

public class AsyncCommand : IAsyncCommand
{
    public event EventHandler CanExecuteChanged;

    private bool _isExecuting;
    private readonly Func<Task> _execute;
    private readonly Func<bool> _canExecute;
    private readonly IErrorHandler _errorHandler;

    public AsyncCommand(
        Func<Task> execute,
        Func<bool> canExecute = null,
        IErrorHandler errorHandler = null)
    {
        _execute = execute;
        _canExecute = canExecute;
        _errorHandler = errorHandler;
    }

    public bool CanExecute()
    {
        return !_isExecuting && (_canExecute?.Invoke() ?? true);
    }

    public async Task ExecuteAsync()
    {
        if (CanExecute())
        {
            try
            {
                _isExecuting = true;
                await _execute();
            }
            finally
            {
                _isExecuting = false;
            }
        }

        RaiseCanExecuteChanged();
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }

    #region Explicit implementations
    bool ICommand.CanExecute(object parameter)
    {
        return CanExecute();
    }

    void ICommand.Execute(object parameter)
    {
        ExecuteAsync().FireAndForgetSafeAsync(_errorHandler);
    }
    #endregion
}

您可能还想阅读this文章。

但是,即使将命令类型更改为AsyncCommand,您在XAML中定义的InvokeCommandAction仍不会调用ExecuteAsync()方法。您最好自己在视图模型中调用它,或者直接调用async方法。例如,您可以通过为PropertyChanged事件连接一个异步事件处理程序来做到这一点:

public ViewModel()
{
    this.PropertyChanged += async (s, e) =>
    {
        switch (e.PropertyName)
        {
            case nameof(DateDebut):
                await GetParametresMatrice();
                //here the method has completed and you can do whatever you want...
                break;
        }
    };
}

答案 1 :(得分:0)

由于在加载页面布局期间绑定了DateEnd数据和DateStart,因此触发了两次您的事件。同样,当您设置新数据模型时,由于相同的原因,它也会触发两次事件。

您可以重新放置逻辑以允许执行命令方法

from flask import Flask 
from flask import send_file 
from redis import Redis, RedisError 
import os 
import socket

Connect to Redis
redis = Redis(host="redis", db=0, socket_connect_timeout=2, socket_timeout=2)

app = Flask(__name__)

@app.route("/") 
def hello():

html = " <b>Container Name:</b> {hostname}<br/>" 


return html.format(hostname=socket.gethostname()), (send_file('counter.mp4', attachment_filename='counter.mp4')