Выполнить асинхронную задачу, изменить значение элемента управления, который запускает событие

#c# #wpf #asynchronous #async-await #dispatcher

#c# #wpf #асинхронный #асинхронное ожидание #диспетчер

Вопрос:

У меня есть метод загрузки, который выполняется асинхронно. Внутри этого метода я изменяю Проверенное состояние радиокнопки.

Это работает нормально, и не имеет значения, выполняю ли я его напрямую или через диспетчер.BeginInvoke .

Однако у RadioButton есть событие «CheckedChanged». Когда я вызываю

 Dispatcher.Invole((Action)()=>{rb.IsChecked=true;}));
  

Я бы ожидал, что мой асинхронный метод будет ждать выполнения события checked changed (которое снова запускает асинхронный метод).

В прилагаемом коде вы увидите, что порядок выполнения:

  1. «BeginInvoke»
  2. «EndInvoke»
  3. «RbChanged»

То, что я хотел бы иметь, это:

  1. «BeginInvoke»
  2. «RbChanged»
  3. «EndInvoke»

Какие-либо варианты для этого?

MainWindow.xaml.cs

  public MainWindow()
        {
            InitializeComponent();
        }

        private async enter code herevoid Window_Loaded(object sender, RoutedEventArgs e)
        {
            await RightAfterLoading();
        }


        private async Task RightAfterLoading()
        {
            Debug.WriteLine("BeginInvoke");
            await Dispatcher.BeginInvoke((Action)(() => { rb.IsChecked = true; }));
            Debug.WriteLine("EndInvoke");
        }

        private async void rb_Checked(object sender, RoutedEventArgs e)
        {
            await SomethingAfterChecked();
        }

        private async Task SomethingAfterChecked()
        {
            string abc = string.Empty;
            await Task.Run(() => abc = "RbCheckedChanged");
            Console.WriteLine(abc);
        }
  

И MainWindow.xaml выглядит так:

 <Window x:Class="AsyncAwaitIssue.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:local="clr-namespace:AsyncAwaitIssue"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        Title="MainWindow"
        Width="525"
        Height="350"
        Loaded="Window_Loaded"
        mc:Ignorable="d">
    <Grid>
        <RadioButton x:Name="rb"
                     Checked="rb_Checked"
                     Content="CheckedOrNot"
                     IsChecked="False" />
    </Grid>
</Window>
  

Ответ №1:

Это сама природа async void методов. Когда вы установите IsChecked , он будет ждать выполнения обработчика событий для измененного события, но когда вы выполняете этот обработчик, все, что вы когда-либо делаете, это запускаете асинхронную операцию. Обработчик завершится до завершения этих асинхронных операций.

В идеале вы должны избегать такой ситуации. Если у вас есть что-то, что должно произойти после работы, которую вы выполняете в событии changed, было бы лучше, если бы это событие change выполнило эту операцию. Если вы не можете, вам нужно будет вручную создать некоторую форму связи между этими разделами кода и связать эти операции вместе довольно плотно.

Комментарии:

1. Спасибо за ваш ответ Servy.

2. Я ожидал такого ответа, но я хотел посмотреть, есть ли решение для этого. Однако нам нужно будет найти другой способ обойти эту «проблему».