Как динамически изменять содержимое текстового блока внутри другого метода?

#c# #wpf #windows-forms-designer

#c# #wpf #windows-forms-designer

Вопрос:

У меня есть метод поиска (расширенный SQL-запрос внутри), который запускается кнопкой «поиск». Я хочу показать «Running …» в текстовом блоке во время выполнения кода и показать «Done», когда он закончится. В идеале сообщение «Готово» также заменяется сообщением «Idle» через несколько секунд.

Соответствующая часть моего кода XAML такова:

 <Button x:Name="MainButton" Click="searchButton_Click" Content="search" ... />
<TextBlock Name="status" Text="Idle" .../>
 

и соответствующая часть моего кода на C # выглядит следующим образом:

 namespace WpfApp5
{

   public partial class MainWindow : Window 
   {


        public MainWindow()
        {
        InitializeComponent();
        }


        private void searchButton_Click(object sender, RoutedEventArgs e)
        {

        this.status.Text="running...";
  
        // make connection

        string mySQLquery= "Do a lot of things here...";

  

        // show the result in a datagrid
        SqlCommand my_cmd = new SqlCommand(mySQLquery, conn);

        DataTable mydt = new DataTable();

        using (SqlDataAdapter a = new SqlDataAdapter(my_cmd))
        {
           a.Fill(mydt);
        }

        this.status.Text="done";

        }
    }
}
 

Что делает этот код, так это то, что он показывает «idle» в текстовом блоке при открытии приложения, а затем не изменяет его, пока процесс поиска не будет завершен; а затем показывает «готово». Таким образом, состояние «выполняется» не отображается.
Я хотел бы иметь решение с минимальными изменениями в логике моего кода. Заранее благодарю.

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

1. Может быть, вы просто слишком быстро видите «выполняется …»? Вы пытались добавить точку останова после этой строки, чтобы проверить, правильно ли она записана?

2. @Rafalon Нет, это не так быстро. Это занимает несколько секунд. Вы имеете в виду, что логика этого кода верна? Я думаю, что здесь есть проблема.

3. Я имею в виду, что мне это кажется правильным, но, возможно, задействован какой-то буфер или что-то в этом роде… Редактировать: хорошо, я не знал, что WPF не будет обновлять пользовательский интерфейс до тех пор, пока метод не будет завершен (о чем я узнал благодаря Quercus ниже)

Ответ №1:

Вам нужно выполнить ваш запрос асинхронно. WPF не будет обновлять пользовательский интерфейс, пока метод не будет завершен. Вы можете пометить свой обработчик как асинхронный и использовать Task.Run для выполнения SQL-запроса:

 private async void searchButton_Click(object sender, RoutedEventArgs e)
{
    this.status.Text="running...";

    // make connection

    string mySQLquery= "Do a lot of things here...";



    // show the result in a datagrid
    SqlCommand my_cmd = new SqlCommand(mySQLquery, conn);

    DataTable mydt = new DataTable();

    await Task.Run(() => {
       using (SqlDataAdapter a = new SqlDataAdapter(my_cmd))
       {
          a.Fill(mydt);
       }
    });

    this.status.Text="done";

    await Task.Delay(2000);
 
    this.status.Text = "idle";

}
 

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

1. Фантастика. Спасибо! Теперь при запуске отображается «выполняется …», а затем «готово» по завершении. Есть ли простой способ заменить «готово» на «простаивает» через несколько секунд?

2. Конечно, добавьте await Task.Delay(2000); this.status.Text="idle"; в конец метода с задержкой в 2 секунды. Однако, если вы нажмете кнопку до того, как done изменится на idle, вы увидите сначала «running», а затем внезапно «idle» — до тех пор, пока два обработчика кнопок будут работать вместе

3. Не могли бы вы добавить это в свой ответ? Я не знаю, куда мне следует добавить эту часть. Я благодарю вас.

Ответ №2:

Вы запускаете searchButton_click функцию в потоке пользовательского интерфейса, пользовательский интерфейс не будет обновляться, пока функция не будет выполнена.

 private void searchButton_Click(object sender, RoutedEventArgs e)
{
    // starts the lambda outside the UI thread
    Task.Run(() =>
    {
        // dispatcher will execute the lambda inside the UI thread
        Application.Current.Dispatcher.Invoke(() =>
        {
            Status.Text = "running...";
        });
        Thread.Sleep(1000);
        Application.Current.Dispatcher.Invoke(() =>
        {
            Status.Text = "done";
        });
        SetDefaultPromise();
    });
}

private void SetDefaultPromise()
{
    Task.Run(() =>
    {
        Thread.Sleep(1000);
        Application.Current.Dispatcher.Invoke(() =>
        {
            Status.Text = "idle";
        });
    });
}
 

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

1. Спасибо. Я не пробовал, потому что предыдущий ответ решил проблему «running …». Но есть ли какой-нибудь способ изменить статус на «idle» через несколько секунд после отображения «готово»?

2. @Iraj Я отредактировал, чтобы учесть ваши потребности.

3. Большое вам спасибо