Асинхронный метод вызывается 2 раза одновременно - PullRequest
0 голосов
/ 23 мая 2019

вот мое беспокойство.У меня есть два DatePicker, которые иногда должны запускаться одновременно (я выбираю агента, получаю дату его начала и дату его окончания).

У меня есть метод, который будет извлекать планирование в соответствии с датамипроблема в том, что одновременно требуется дата начала + дата окончания + нормальный триггер (когда я выбираю агента, отображается его расписание по умолчанию). Таким образом, результат дает мне несколько данных одновременно (я получаюсообщение об ошибке "нет планирования" + планирование позади, что не имеет никакого смысла)

Вот код:

        <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 изменяются одновременно.

EDIT 2:

end

Когда я отображаю результат, у меня есть расписание + сообщение об ошибке.Что обычно невозможно, Planning.count не может быть> 1 И <1 </p>

Любые советы?

Заранее спасибо.

Ответы [ 2 ]

1 голос
/ 23 мая 2019

Похоже, ваша основная проблема в том, что ваша реализация ICommand (RelayCommand) не является асинхронной или ожидаемой.Если бы это было так, вы могли бы ожидать команду LoadMatrice.

Вы найдете пример асинхронной ICommand реализации здесь .

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
}

Вы также можете прочитать эту статью.

Но даже если вы измените тип вашей команды на AsyncCommand, InvokeCommandAction, который вы определили в своем XAML, все равно не будет вызыватьметод ExecuteAsync().Вы бы лучше называли это сами или вызывали асинхронный метод напрямую в своей модели представления.Например, вы можете сделать это, подключив обработчик асинхронных событий для события 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;
        }
    };
}
0 голосов
/ 23 мая 2019

Ваше событие сработало дважды из-за привязки данных DateEnd и DateStart во время загрузки макета страницы. Кроме того, когда вы устанавливаете новую модель данных, она тоже вызывает события дважды по той же причине.

Вы можете переместить свою логику для разрешения выполнения методу команды

 public bool CanExecute(object parameter)
    {
        MainWindowViewModel viewModel = parameter as MainWindowViewModel;
        if (viewModel.isNeedToCheck && viewModel.IsWholeModelSet)
            return false;
        return true;
    }
...