В 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. Я нашел следующий шаблон, чтобы хорошо работать для меня.

В основной форме вам необходимо выполнить следующие шаги.

  1. Создайте BackgroundWorker для выполнения длительной операции.
  2. Запустите BackgroundWorker.
  3. Показать форму ожидания в виде модального диалога.
// 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;
}
Другие вопросы по тегам