#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. Большое вам спасибо