-1

i have an issue where i need to update text within a form run in a thread but cannot work how exactly this would be acheivable, here's my existing code:

public partial class Class1: Form
{
    LoadText = loadText;
    ResourceName = resourceName;

    static private void ShowForm()
    {
        LoadForm = new Class1(LoadText, ResourceName);
        Application.Run(LoadForm);
    }

    static public void ShowLoadScreen(string sText, string sResource)
    {
        LoadText = sText;
        ResourceName = sResource;

        Thread thread = new Thread(new ThreadStart(Class1.ShowForm));
        thread.IsBackground = true;
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    }
}

Now i need to change the text in a textbox under the newly started form, this needs to be performed from the theoretical 'Class2':

class Class2
{
   public void UpdateThreadFormTextbox
   {
      Class1.ShowLoadScreen("text", "text");
      //Change textbox in the thread instance of Class1 form
   }
}

I've looked into using 'Invoke' but i can't use that from Class2, does have a solution that will enable me to update the text in the Class1 thread instance from Class2?

Dan Hall
  • 1,474
  • 2
  • 18
  • 43

2 Answers2

2

Just use the Invoke from Class1:

public partial class Class1: Form
{
    private static Class1 LoadForm;

    static private void ShowForm()
    {
        LoadForm = new Class1(LoadText, ResourceName);
        Application.Run(LoadForm);
    }

    static public void ShowLoadScreen(string sText, string sResource)
    {
        LoadText = sText;
        ResourceName = sResource;

        Thread thread = new Thread(new ThreadStart(Class1.ShowForm));
        thread.IsBackground = true;
        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    }

    public static void SetText(string text)
    {
        Class1.LoadForm.textBox1.Invoke(new Action(() => Class1.LoadForm.textBox1.Text = text));
    }
}

And then use that method from Class2:

class Class2
{
   public void UpdateThreadFormTextbox
   {
      Class1.ShowLoadScreen("text", "text");
      Class1.SetText("TEXT");
   }
}
Romano Zumbé
  • 7,893
  • 4
  • 33
  • 55
  • Thanks but to call SetText in that manner the method SetText must be static, that means it then has no access to the label/textbox of the form instance...or am i missing something? – Dan Hall Jun 19 '17 at 08:50
  • `SetText` isn't static, and if it is static then it can't access `textBox1`. – ColinM Jun 19 '17 at 08:50
  • Ah ok, sorry. Got that wrong. Is `Loading` the Form with the TextBox? – Romano Zumbé Jun 19 '17 at 08:52
  • That'S what I'm saying, there lies the problem with the above code from Romano. In that example Class.SetText("TEXT") is being called which requires SetText to be static. If the class is static that it has no access to the form instance..Here lies my problem. – Dan Hall Jun 19 '17 at 08:52
  • Sorry the example was a little incorrect as i change names of the some elements. It's corrected now. – Dan Hall Jun 19 '17 at 08:53
  • I've updated my answer. This should work then. – Romano Zumbé Jun 19 '17 at 08:55
  • Loading is now renamed to Class1 (correctly) so that'S my problem, i need to call 'SetText' as a static method but if i do that i have no acess to the threaded form instance. – Dan Hall Jun 19 '17 at 08:55
  • Forgot to make the SetText method static. Added that – Romano Zumbé Jun 19 '17 at 08:57
  • You're still trying to access `textBox1` from a static context. – ColinM Jun 19 '17 at 08:59
  • It works because the static member has a reference to the created object. From there you can access textbox1. Give it a try. It will work ;-) – Romano Zumbé Jun 19 '17 at 09:00
  • Thanks :) but shouldn't Class1.textBox1.Invoke(new Action(() => Class1.textBox1.Text = text)); be LoadForm.loadMessage.Invoke(new Action(() => LoadForm.loadMessage.Text = value)); – Dan Hall Jun 19 '17 at 09:03
  • I changed that in my last edit – Romano Zumbé Jun 19 '17 at 09:04
  • I mean under SetText, Class1.LoadForm.textBox1.Invoke should be LoadForm.textBox1.Invoke? – Dan Hall Jun 19 '17 at 09:05
  • Thats no difference. You could use it in both ways. Since your in the implementation of Class1 you can access the static member directly or call it via the class name – Romano Zumbé Jun 19 '17 at 09:07
  • Thanks :) Works Nicely! – Dan Hall Jun 19 '17 at 09:42
1

You can also achieve this by passing an instance of the text box to your UpdateThreadFormTextBox method and calling Invoke on that from your Class2

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    private void Form1_Load(object sender, EventArgs e)
    {
        // Create instance of Class2
        Class2 secondClass = new Class2();
        // Create a new thread, call 'UpdateThreadFormTextbox' 
        // and pass in the instance to our textBox1, start thread
        new Thread(() => secondClass.UpdateThreadFormTextbox(textBox1)).Start();
    }
}

public class Class2
{
    public void UpdateThreadFormTextbox(TextBox textBox)
    {
        textBox.Invoke(new Action(() => textBox.Text = "Set from another Thread"));
    }
}
ColinM
  • 2,622
  • 17
  • 29
  • 1
    This won't work. It doesn't take into account the order classes are instantiated. First instance is of type Class2, this calls the static method `ShowLoadScreen` of Class1 which then creates an instance of itself. Your code is doing something else – Romano Zumbé Jun 19 '17 at 09:20
  • That is true, I will leave this as an example should Op wish to refactor their code. – ColinM Jun 19 '17 at 09:30