Osadzanie metod asynchronicznych wewnątrz funkcji zdarzenia

0

Cześć,

mam pytanie, bo szczerze, to nie jestem pewien czy nawet poprawnie to ująłem w temacie, ale mam sobie jakąś funkcję dla zdarzenia jak poniżej. Mam jakieś tam metody asynchroniczne, w tym wbudowany dialog.ShowAsync(), ale domyślam się, że to jest niepoprawne. Już sam async void mi nie pasuje, bo mi coś tam VS podkreśla na zielono i mówi, że async i void, to nie tak. :)

No więc teoretycznie powinienem używać Task, ale Task w tej sytuacji nie wchodzi w grę, bo zwyczajnie nie będzie działać. Więc moje pytanie brzmi w jaki sposób poprawnie to rozegrać? Jak poprawnie oczekiwać na rezultat jakiejś metody asynchronicznej w tej sytuacji?

        private async void BtCheckAll_Click(object sender, RoutedEventArgs e)
        {
            var dialog = YesNoMessage("Jesteś tego pewien? Aktualny wybór zostanie usunięty.", "Uwaga");

            var result = await dialog.ShowAsync();

            if (result == dialog.Commands[0])
            {
                PRFrameLoadProgress.Visibility = Visibility.Visible;
                PRFrameLoadProgress.IsActive = true;

                WGridView.SelectAll();

                await SaveSelectedWAsync();

                PRFrameLoadProgress.Visibility = Visibility.Collapsed;
                PRFrameLoadProgress.IsActive = false;
            }
        }

Ogólnie pomyślałem o czymś takim:

        private async Task WaitForAnwserAsync()
        {
            var dialog = YesNoMessage("Jesteś tego pewien? Aktualny wybór zostanie usunięty.", "Uwaga");

            var result = await dialog.ShowAsync();

            if (result == dialog.Commands[0])
            {
                PRFrameLoadProgress.Visibility = Visibility.Visible;
                PRFrameLoadProgress.IsActive = true;

                WGridView.SelectAll();

                await SaveSelectedWAsync();

                PRFrameLoadProgress.Visibility = Visibility.Collapsed;
                PRFrameLoadProgress.IsActive = false;
            }
        }

        private void BtCheckAll_Click(object sender, RoutedEventArgs e)
        {
            WaitForAnwserAsync().ConfigureAwait(false);
        }

Czuję jednak, że ominąłem po prostu komunikat, a nie rozwiązałem problem. Ktoś może mi wytłumaczyć jak najlepiej radzić sobie z czymś takim? Dodam, że chodzi o C# 7.2. Dzięki.

0

IMO nie ma nic złego w async void (w kontekście metody obsługi zdarzenia), ani też VS nie podkreśla mi takiej konstrukcji jako takiej w żaden sposób. Jaki masz komunikat do tej podpowiedzi, że niby się mu coś nie podoba?

0

Dla C# 7.2, ale już nie po dzisiejszej aktualizacji systemu, albo coś zmieniłem w projekcie, a nie wiem co. :D

void nie zwróci Ci rezultatu, a Task tak, stąd od void Task jest lepszy, bo łatwiej wychwycić problem z realizacją zadania. Problem pojawia się właśnie w sytuacji jak w pierwszym poście. Nie zastąpię Taskiem vioda dla tego typu zdarzenia jak Click, czy SelectionChanged, bo to nie zadziała z Task.

BtCheckAll.Click += BtCheckAll_Click;
BtCheckAll.Click -= BtCheckAll_Click;

Podejrzewam, że zaczną odchodzić od async void i zwyczajnie dostałem info, że po pierwsze, metoda asynchroniczna powinna być typu Task, a nie void, a po drugie nazwa powinna kończyć się na Async. Nie zdziwi mnie jak za rok wyświetli mi się "Asynchronous void methods are deprecated". xD

0

Nie odejdą od async void, bo to zepsułoby kompatybilność, nie działałoby w VB.NET i zmieniłoby sposób wykonania programu (że o semantyce już nie wspomnę). async void to niestety potworek, na który nie ma ładnego obejścia, więc używa się go tylko tam, gdzie jest to niezbędne, czyli chyba tylko w event handlerach.

0

No właśnie dlatego pytam o to dziwadło. Osobiście w event handlerach nie będę korzystał, bo to da się obejść a jak już się użyje, to z czasem bywa, że i tak trzeba się z tego wycofać. Task jest spoko, bo łatwiej się obsługuje wyjątki. Znalazłem już kilka sposobów na obejście tego i będę unikał, bo potrafią się dziać dziwne rzeczy.

1 użytkowników online, w tym zalogowanych: 0, gości: 1