В C# как вы блокируете форму?
Я пытаюсь заблокировать основную форму, пока на экране отображается окно ожидания, но оно не работает. Вот моя дилемма.
У меня есть 2 формы. Основная форма, в которой пользователь нажимает кнопку обновления, чтобы загрузить список серверов SQL, и форму "Пожалуйста, подождите", которая отображается во время загрузки списка. Поток SQL Server по умолчанию является отдельным потоком при использовании C#, и он блокирует основной поток для обработки запроса SQL.
Я могу добавить фонового работника, но затем я не могу обновить поле со списком, чтобы показать список в качестве элемента управления пользовательского интерфейса. Если я использую обработчик для этого, мой show_dialog() для окна "Пожалуйста, подождите" перестанет блокировать основную форму.
Как вообще возможно заблокировать эту форму без запуска очереди левого клика после того, как основной поток снова станет активным? Я добавил код, который должен быть выполнен, пока пользователь ждет.
public void PullServers()
{
bool ServersFound = false;
foreach (string Value in SQL.LocateSqlInstances())
{
this.cmbServer.Items.Add(Value);
ServersFound = true;
}
if (!ServersFound)
{
this.cmbServer.Items.Add(Strings.Lang("ddServerNoneFound"));
this.cmbServer.SelectedIndex = 0;
}
else
{
if (!s.empty(General.setting("SQLSERVER")))
{
this.cmbServer.Text = General.setting("SQLSERVER");
}
else
{
this.cmbServer.SelectedIndex = 0;
}
}
this.picRefreshServers.Image = Properties.Resources.Refresh;
}
public static Array LocateSqlInstances()
{
using (DataTable sqlSources = System.Data.Sql.SqlDataSourceEnumerator.Instance.GetDataSources())
{
string Servers = null;
foreach (DataRow source in sqlSources.Rows)
{
string instanceName = source["InstanceName"].ToString();
if (!s.empty(instanceName))
{
Servers += source["ServerName"].ToString() + "\\" + instanceName + "[[SERVBREAK]]";
}
}
string[] ServersList = Servers.Split(new string[] { "[[SERVBREAK]]" }, StringSplitOptions.RemoveEmptyEntries);
return ServersList;
}
}
1 ответ
Я думаю, что вы на правильном пути с BackgroundWorker. Я нашел следующий шаблон, чтобы хорошо работать для меня.
В основной форме вам необходимо выполнить следующие шаги.
- Создайте BackgroundWorker для выполнения длительной операции.
- Запустите BackgroundWorker.
- Показать форму ожидания в виде модального диалога.
// Step 1:
BackgroundWorker bg = new BackgroundWorker()
bg.DoWork += new DoWorkEventHandler(bg_DoWork);
bg.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bg_RunWorkerCompleted);
// Step 2:
bg.RunWorkerAsync();
// Step 3:
waitingForm = new WaitingForm();
waitingForm.ShowDialog();
Как вы знаете, вы не можете обновить пользовательский интерфейс из bg_DoWork
обработчик, так как он не работает в потоке пользовательского интерфейса. Так что просто получите необходимые данные здесь и передайте их bg_RunWorkerCompleted
обработчик с использованием параметра e.Result.
private void bg_DoWork(object sender, DoWorkEventArgs e)
{
Array servers = SQL.LocateSqlInstances();
e.Result = servers;
}
bg_RunWorkerCompleted
работает в потоке пользовательского интерфейса, поэтому безопасно обновлять элементы управления здесь. Здесь вы должны закрыть форму ожидания и затем обновить свой пользовательский интерфейс.
private void bg_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
// Close the Waiting form.
waitingForm.Close();
// Retrieve the result of bg_DoWork().
Array servers = e.Result as Array;
bool ServersFound = false;
foreach (string Value in servers)
{
this.cmbServer.Items.Add(Value);
ServersFound = true;
}
if (!ServersFound)
{
this.cmbServer.Items.Add(Strings.Lang("ddServerNoneFound"));
this.cmbServer.SelectedIndex = 0;
}
else
{
if (!s.empty(General.setting("SQLSERVER")))
{
this.cmbServer.Text = General.setting("SQLSERVER");
}
else
{
this.cmbServer.SelectedIndex = 0;
}
}
this.picRefreshServers.Image = Properties.Resources.Refresh;
}