开发者

C# Thread dataGridView and Loading

开发者 https://www.devze.com 2023-04-11 22:57 出处:网络
Im trying to load a dataGridView which takes some time, so ive come up with an idea of hiding the datagridview and put an image over the top which says Loading... when finished, the image goes away an

Im trying to load a dataGridView which takes some time, so ive come up with an idea of hiding the datagridview and put an image over the top which says Loading... when finished, the image goes away and the datagrid reappears. Ive tried to do this using threading but having no luck.

Can somebody tell me if i am approaching this in the right way?

Label loadingText = new Label();
PictureBox loadingPic = new PictureBox(); 

private void TelephoneDirectory_Load(object sender, EventArgs e)
    {
        dataGridView1.Visible = false;

        Thread i = new Thread(LoadImage);
        i.Start();
        Thread t = new Thread(LoadData);
        t.Start();
    }
void LoadImage()
    {
        if (this.InvokeRequired)
        {
            this.Invoke(new MethodInvoker(LoadImage));
        }
        else
        {
            loadingPic.Image = Properties.Resources.ReportServer;
            loadingPic.Location = new Point(0, 0);
            loadingPic.Name = "loadingPic";
            loadingPic.Dock = DockStyle.Fill;
            loadingPic.SizeMode = PictureBoxSizeMode.CenterImage;
            loadingText.Text = "Loading, please wait...";
            loadingText.Name = "loadingText";
            loadingText.TextAlign = ContentAlignment.MiddleCenter;
            loadingText.Size = new Size(this.Size.Width, 30);
            loadingText.Font = new System.Drawing.Font("Segoe UI", 9);
            loadingText.Location = new Point(0, (this.Size.Height / 2 + 10));
            this.Controls.AddRange(new Control[] { loading开发者_JAVA技巧Pic, loadingText });
            loadingText.BringToFront();
        }
    }
private void LoadData()
    {
        if (dataGridView1.InvokeRequired)
        {
            dataGridView1.Invoke(new MethodInvoker(this.LoadData));
        }
        else
        {

            DirectorySearcher sea = null;
            DirectoryEntry dir = null;
            DirectoryEntry d = null;
            string domainname = System.DirectoryServices.ActiveDirectory.Domain.GetComputerDomain().Name;
            domainname = domainname.Replace(".", ",DC=");
            try
            {

                dir = new DirectoryEntry();
                dir.Path = "LDAP://DC=" + domainname;

                sea = new DirectorySearcher(dir);

                sea.Filter = "(&(objectClass=user)(extensionAttribute1=1)(telephoneNumber=*))";

                sea.PageSize = 2000;
                SearchResultCollection res = sea.FindAll();

                foreach (SearchResult result in res)
                {
                    //DO ALL MY STUFF

                    dataGridView1.Rows.Add(row);
                }

            }
            catch { }
            LoadDataComplete();
        }
    }
void LoadDataComplete()
    {

        PictureBox loadingGraphic = this.Controls["loadingPic"] as PictureBox;

        Label LoadingLabel = this.Controls["loadingText"] as Label;

        DataGridView dataGrid = this.Controls["dataGridView1"] as DataGridView;
        dataGrid.Visible = true;

        LoadingLabel.Visible = false;
        LoadingLabel.Dispose();

        loadingGraphic.Visible = false;
        loadingGraphic.Dispose();

        dataGridView1.Sort(dataGridView1.Columns[0], ListSortDirection.Ascending);
        dataGridView1.ClearSelection();
    }


Spawning threads for this might not be the best idea, you could use ThreadPool or BackgroundWorker

Loading image should be fast enough that you could just do it synchronously, so make sure you actually need to do some operation on the other thread before you actually need it.

Ask yourself questions like: what if actually my image will load later then my dataTable? ("but it loads faster every time I checked" is not an valid argument when talking about threads)

At the beginning of your methods you are using .Invoke which basically means "wait for UI thread and invoke my code on it synchronously" which bombards your whole idea.

Try something like this:

  1. Load image synchronously
  2. Use ThreadPool to load your DataTable in it, but without using .Invoke
  3. When it's loaded and you need to interact with UI -> then put your code in .Invoke()

Pseudocode coud look like this:

private void TelephoneDirectory_Load(object sender, EventArgs e)
{
    dataGridView1.Visible = false;
    LoadImage();

    ThreadPool.QueueUserWorkItem(new WaitCallback(o => LoadData()));
}

void LoadData()
{
    //...Do loading
    //but don't add rows to dataGridView

    if (dataGridView1.InvokeRequired)
    {
        //Invoke only the ui-interaction code
        dataGridView1.Invoke(new MethodInvoker(this.LoadDataComplete));
    }

}

void LoadDataComplete() 
{
    foreach (SearchResult result in res)
    {
        //DO ALL MY STUFF
        //If do all my stuff is compute intensive and doesn't require UI,
        //put it before Invoke() (like here)
        dataGridView1.Rows.Add(row);
    }
    //Rest of code
 }
0

精彩评论

暂无评论...
验证码 换一张
取 消