2
votes

I have a TabControl with three tabs in it. Each tab contains a DataGridView. When I display the TabControl for the first time, I databind my source data to each of the three DataGridViews and after some delay, the TabControl appears on the screen on the default (1st) tab.

When I click on either of the other two tabs (for the first time only), there is a very lengthy delay before each tab is shown. Once any of the tabs has been displayed at least once, I can freely switch between tabs very quickly. Is there any way that I can pre-load or pre-render these tabs so that I don't experience this delay on the first display?

Perhaps I can do something in a thread in the background to pre-load the remaining tabs. Or perhaps someone has written an extension of the TabControl which does this for me.

Any help is appreciated.

Edit: As requested by krawl, here is the code I am using that binds the data to the DataGridViews.

public void LoadNewDataBase(string filename)
{
    //  Create the database connection
    mySQL.CreateNewDataBase(filename);

    // Display the DF DataSet
    dataGridViewDF.DataSource = GetDataSet("DF").Tables[0].DefaultView;
    dataGridViewSA.DataSource = GetDataSet("SA").Tables[0].DefaultView;
    dataGridViewGPS.DataSource = GetDataSet("GPS").Tables[0].DefaultView;

    dataGridViewDF.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
    dataGridViewSA.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;
    dataGridViewGPS.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCells;

    // Preload the tabs
    for (int i = tabControl1.TabCount - 1; i >= 0; i--)
    {
        tabControl1.SelectedIndex = i;
        tabControl1.Invalidate();
        tabControl1.Update();
    }
}

private DataSet GetDataSet(string tableName)
{
    DataSet ds = new DataSet();
    mySQL.GetDataSet("SELECT * FROM " + tableName).Fill(ds);
    return ds;
}

This operation is not threaded. As a temporary solution to my problem, I included that for loop into my LoadNewDataBase method for iterating over each tab and displaying it. To obfuscate this operation from the user, I overlay a graphic on top of my TabControl to indicate that the control is loading and then I hide it afterwards (code for that not included). It's useful as a workaround but not an elegant solution.

3
I think BackGround Worker will work here when your app is opening - Rafay Zia Mir
Right but my question is what methods to invoke in order to pre-load the tabs. I can setup the threading or bgWorker. I don't know the methods to call within the threading to do the pre-load. I am also still fairly certain that even if I use threading/bgWorker, I will need to invoke the TabControl to make it paint itself. - Michael Mankus

3 Answers

2
votes

I would suggest posting some code on how you are attempting to load the tabs. I performed a test with the following code with no interface lag whatsoever.

    protected void Form1_Load(object sender, EventArgs e)
    {
        dataGridView1.DataSource = GetTable();
        dataGridView2.DataSource = GetTable();
        dataGridView3.DataSource = GetTable();
    }

    private DataTable GetTable()
    {
        DataTable table = new DataTable();
        for (int i = 0; i < 6; i++)
        {
            table.Columns.Add("Col" + i.ToString(), typeof(string));
        }

        for (int i = 0; i < 1000; i++)
        {
            table.Rows.Add(GetRandomString(), GetRandomString(), GetRandomString(), GetRandomString(), GetRandomString(), GetRandomString());
        }

        return table;
    }


    private Random rand = new Random();
    private string validChars = "0123456789abcdefghijklmnopqurstuvwyz";

    private string GetRandomString()
    {
        StringBuilder builder = new StringBuilder();

        char[] c = new char[rand.Next(15, 20)];
        for (int i = 0; i < c.Length; i++)
        {
            c[i] = validChars[rand.Next(0, validChars.Length - 1)];
        }

        return new string(c);
    }
1
votes

A data bound control doesn't update until the control is made visible. The workaround is to make the other tabs visible. Switching to the other tab and going back to the previous immediately before the form is visible doesn't work. In your background thread you can do something similar to this:

tabControl.SelectedTab = tabPage2; 
tabPage2.BindingContextChanged += (_, __) => 
     tabControl.SelectedTab = tabPage1; 

tabControl.SelectedTab = tabPage3;
tabPage3.BindingContextChanged += (_, __) => 
     tabControl.SelectedTab = tabPage1; 
0
votes

I just maid the code by Jacob so that it can be use as a function

private void next_TabPage(TabPage tabpage1, TabPage tabpage2)
    {
        TabControl.SelectedTab = tabpage2;
        tabpage2.BindingContextChanged += (_, __) =>
        TabControl.SelectedTab = tabpage1;
    }