JCMtz55
JCMtz55

Reputation: 11

Use Controls created in a Thread

Hi I'm trying to call a method in another class that has an Arraylist of textboxes into a panel in the main form currently it works but I need to put the method

I already have try

ThreadStart starter = () => draw.DynamicTextBox(c, f);
Thread thread = new Thread(starter);
thread.Start();

but it gives me the object reference not set to an instance of an object exception or that the Arraylist is null

//Code in MainForm
public generator draw = new generator();
private void Button1_Click(object sender, EventArgs e)
    {
        int c = Convert.ToInt16(txbColumn.Text);
        int f = Convert.ToInt16(txbRow.Text);

        draw.DynamicTextBox(c, f); //needs to be on a Thread

        foreach (Control txtb in draw.textboxList)
        {
            Paneltxb.Controls.Add(txtb); 
        }

    }

//Code in Generator Class
 public class generator
{
    public ArrayList textboxList;


    public void DynamicTextBox(int c, int f )
    {
        textboxList = new ArrayList();
        int n = 0;
        for (int x = 0; x < f; x++)
        {
            for (int y = 0; y < c; y++)
            {
                        n++;
                        TextBox txtb = new TextBox();
                        txtb.Text = "txb " + n;
                        txtb.Name = "txb" + n;

                        txtb.Location = new Point(y * 100, x * 20);
                        textboxList.Add(txtb);

            }

        }
    }


}

Upvotes: 0

Views: 111

Answers (2)

It's telling you the ArrayList is null because the ArrayList is null. At that point in time.

    ThreadStart starter = () => draw.DynamicTextBox(c, f);
    Thread thread = new Thread(starter);
    thread.Start();

    //  The thread just started running. The textboxes have not been created yet. 
    //  draw.textboxList has not been given a value yet. It's null.
    //  The stuff in the other thread is happening in a different thread, 
    //  at its own pace. 
    //  The whole point of putting it in another thread is that the rest of the code 
    //  in *this* thread continues executing before the other thread finishes. You can't
    //  ever make any assumptions about when stuff in another thread happens, unless you 
    //  write code to explicitly synchronize the two, which is a proverbially tricky 
    //  business. 

    foreach (Control txtb in draw.textboxList)
    {
        Paneltxb.Controls.Add(txtb); 
    }

If you want to wait to use the results of the other thread until it's finished creating them, the most obvious way to be sure of that happening is just do it in the other thread. Try something like this:

ThreadStart starter = () => {
    draw.DynamicTextBox(c, f);

    //  We do this Invoke thing because we're messing with UI, which has to 
    //  be done in the UI thread. We're in another thread, so what Invoke
    //  does for us is it reaches into the UI thread and executes its code 
    //  there. It does this using magic thread runtime pixies or something. 
    //  I don't know what. 
    this.BeginInvoke(new MethodInvoker(delegate {
        foreach (Control txtb in draw.textboxList)
        {
            Paneltxb.Controls.Add(txtb); 
        }
    });
};

I suspect that'll blow up on you anyway because you're creating the TextBoxes out of the UI thread. Good luck.

Upvotes: 3

brakeroo
brakeroo

Reputation: 1447

You can try async/await (see below) however I'm not sure it's worth using a new thread via Task.Run() since it does not seem you need to "parallelize" work:

private async void Button1_Click(object sender, EventArgs e)
{
    int c = Convert.ToInt16(txbColumn.Text);
    int f = Convert.ToInt16(txbRow.Text);

    await Task.Run(()=> draw.DynamicTextBox(c, f));

    foreach (Control txtb in draw.textboxList)
    {
        Paneltxb.Controls.Add(txtb); 
    }

}

public class generator
{
public ArrayList textboxList;
...
public void DynamicTextBox(int c, int f )
{
 ...
}...

}

One reason I am suggesting async/await pattern is not having to worry about the dipatcher when you're accessing UI elements. The code after the await will run on the UI thread since await captures the UI sync context.

Upvotes: 0

Related Questions