简体   繁体   中英

In C#, how do you lock a form?

I'm trying to lock the main form while a please wait box is shown on the screen, but it won't work. Here's my dilemma.

I have 2 forms. The main form that the user clicks a refresh button to load the list of SQL Servers, and a Please wait form that shows while it's loading the list. The SQL Server thread is a separate thread by default while using C# and it locks out the main thread in order to process the SQL request.

I can add a background worker, but then I can't update my combo box to show the list as its a UI control. If I use a handler for that, my show_dialog() for the please wait box will stop locking down the main form.

How is it even possible to lock this form down without the left click queue being run after the main thread goes active again? I added the code that needs to be executed while the user waits.

    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;
        }
    }

I think you are on the right track with a BackgroundWorker. I have found the following pattern to work well for me.

In your main form, you need to perform the following steps.

  1. Create a BackgroundWorker to perform the long running operation.
  2. Start the BackgroundWorker.
  3. Display the waiting form as a modal dialog.
// 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();

As you know, you can't update the UI from the bg_DoWork handler since it does not run on the UI thread. So just get the data you need here and pass it on to the the bg_RunWorkerCompleted handler using the e.Result parameter.

private void bg_DoWork(object sender, DoWorkEventArgs e)
{
    Array servers = SQL.LocateSqlInstances();
    e.Result = servers;
}

The bg_RunWorkerCompleted runs on the UI thread so it is safe to update your controls here. This is where you should close the waiting form and then update your UI.

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;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM