So here I am back again with my tail between my legs.

I've spent the whole day trying to update my form lable during runtime.
I got there in the end with what I think is threadsafe, then only to spend a few more hours trying do it from outside the form class and failing :|

Here is some short reproducer code to illustrate my goal in the hope someone might be able to assist.

namespace daniwebexample
{
    public partial class Form1 : Form
    {

        Thread NewThread;

        public delegate void UpdateLabel(string text);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            NewThread = new Thread(new ThreadStart(MyNewThread));
            NewThread.Start();
        }


        public void _UpdateLabel(string text)
        {
            if (label1.InvokeRequired)
            {
                UpdateLabel updt = new UpdateLabel(_UpdateLabel);
                Invoke(updt, new object[] { text });
            }
            else
            {
                label1.Text = text;
                label1.Refresh();
            }
        }


        public void MyNewThread()
        {
            _UpdateLabel("New Text");
        }

    }

    public class OtherClass
    {
        public void MyNewThread()
        {
            Form1._UpdateLabel("New Text"); //I thought I could use delegate from here.
        }
    }
}

I am having a torrid time, I've tried creating a new instance of form1 and calling delegate with that, but I need the current instance. And as I understand it, I cannot have a static form, and even if I could I'd still need an instance reference, and I cannot get that reference from Application.Run(new Form1); in the programs Main()

Basically, I've just run out of ideas to try, and here I am wringing my preverbial cap.

Recommended Answers

All 10 Replies

This method

public void _UpdateLabel(string text) {
    if (label1.InvokeRequired) {
        UpdateLabel updt = new UpdateLabel(_UpdateLabel);
        Invoke(updt, new object[] { text });
    } else {
        label1.Text = text;
        label1.Refresh();
    }
}

Is calling itself to update the label. You need to call a different method:

public void _UpdateLabel(string text) {
    if (label1.InvokeRequired) {
        UpdateLabel updt = new UpdateLabel(DoUpdate);
        Invoke(updt, new object[] { text });
    } else {
        DoUpdate(text);
    }
}

private void DoUpdate(String text) {
    label1.Text = text;
}

Thanks for the tip, although the way I wrote it works fine, I guess its best to do it as shown in your correction.

My problem still remains though, of updating the label from outside the Form1 class.

I think my problem here is to do with delegates, its my first attempt to use one and I thought that was the whole point of a delegate to be able to call a method on an instance of a class from outside it.

Still at square 1 :(

Not sure what problem you are having. You can call the _UpdateLabel method anywhere you want, it should update the label on the GUI thread. You only need to have a reference to the form to do so. The delegate is for the Invoke method, you don't need to use it anywhere else.

If I understand you well, you would like to update a label on from1 from some other form, am I right?
For this you do not need delegates at all, and you do not need to start a new Thread either.
You can do it:

//form1:
public void UpdateLabel(string item)
{
    this.label1.Text = item;
}

//form2:
Form1 f1;
public Form2(Form1 _f1)
{
    //constructor of form2
    Initializecomponent();
    this.f1 = _f1;
}

private void button1_ClickUpdateLabelOnform1(objec sender, EventArgs e)
{
    f1.UpdateLabel("New text to pass to form1 form form2");
}

Thats it.

here is my latest attempt, which is as far as I have gotten except it still does not update my label.

using System;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;
using System.Collections.Generic;



namespace daniwebexample
{
    public partial class Form1 : Form
    {

        Thread NewThread;

        public delegate void UpdateLabel(string text);

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            OtherClass otherclass = new OtherClass();
            NewThread = new Thread(new ThreadStart(otherclass.MyNewThread));
            NewThread.Start();
        }


        public void _UpdateLabel(string text)
        {
            if (label1.InvokeRequired)
            {
                UpdateLabel updt = new UpdateLabel(DoUpdate);
                Invoke(updt, new object[] { text });
            }
            else
            {
                DoUpdate("New Text");
            }
        }


        private void DoUpdate(string text)
        {
            label1.Text = text;
            label1.Refresh();
        }

        //public void MyNewThread()
        //{

        //    _UpdateLabel("New Text");
        //    //label1.Refresh();
        //}

    }

    public class OtherClass
    {
        public void MyNewThread()
        {
            Console.WriteLine("in OtherClass"); //my thread has started as this shows up in output
            Form1 form1 = new Form1();
            form1._UpdateLabel("New Text"); // This does not update the label text
        }
    }
}

@Momerath
I cannot see the _UpdateLabel() Method from outside of the Form1 class, this is where I'm stuck, how can I get a reference to the already instanciated Form1?

@Mitja Bonca
No, Im not using any other form, I just have another class reading a file for instance, when it has processed the file, I want it to display the results in the Form1 GUI, I spent a full day yesterday to learn you need a delegate to do this in a safe fashion.

This code is not so good. You have already opened Form1, and its not a good practice to create a new instance of Form1.
Better would be as I showed you, to pass an instance of form1 as parameter to the class, where you would like to use it,

private void button1_Click(object sender, EventArgs e)
        {
            OtherClass otherclass = new OtherClass(this);//ADDED this- its a instance of Form1
            NewThread = new Thread(new ThreadStart(otherclass.MyNewThread));
            NewThread.Start();
        }

////////////////////////
    public class OtherClass
    { 
        Form1 form1;
        //constructor:
        public OtherClass(Form1 _f1)
        {
          this.form1 = _f1;
        }
        public void MyNewThread()
        {
            Console.WriteLine("in OtherClass"); //my thread has started as this shows up in output            
            form1._UpdateLabel("New Text"); // This does not update the label text
        }
    }
commented: very very helpful info to a newb like me. +1

Mitja Bonca

Thank you so much, I was missing a major part of code there, as you can probably tell I'm quite new to OOP.

Your example works a great as expected.

Now to see if I can work that into my app (which has mostly static classes) :S

Thanks guys, I needed a little help to progress further today, appreciate your time.

You can also get forms from Application.OpenForms:

Application.OpenForms["Form1"]._UpdateLabel("New Text"); // by name
Application.OpenForms[0]._UpdateLabel("Newer Text"); // by index

As a side note, we were talking about runtime changing of a controls name, well this is one reason why you would want to do so. If you open 10 Form1 all with the same name, you can't tell which one is which :)

Thanks.

I couldnt find a way to update from a different thread ouside the Form1 class.

For reference, I worked around it like this.

The rest of my app, and its different classes update a static classes properties, and the thread in the Form1 class updates the label text directly from it.

Thing is, its running in a loop checking for a change, and I want to move away from loops and what not, so dont be surprised if you see my next question is regarding events, and the possibility of using the current delegate to deal with one for me.

:)

Thanks again all

Solved.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.