Question How to write WindowsForm textbox component from another class.

Almatea

New member
Joined
Mar 20, 2021
Messages
1
Programming Experience
Beginner
Somebody help me? Please?

I am trying to write to textbox component located on WindowsForm from another class.
What I did wrong? Simple form is started by default form load.
After that separate 'Nonameclass' class with internal timer is created.
Timer is running. Till now it works.
I am trying to show current value in textbox located on that windowsform and I see nothing.
Can somebody help me with working solution please?


code:
namespace Test_CSharp
{
    public partial class Form1 : Form
    {
        public static Form1 form1;

        public Form1()
        {
            InitializeComponent();
            form1 = this;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            Run_Nonameclass();
        }

        private void Run_Nonameclass()
        {
            Nonameclass newNonameclass = new Nonameclass();
        }

    }
}

namespace Test_CSharp
{
    class Nonameclass
    {

        private System.Timers.Timer mycounter;
        public int cnt;

        Form1 frm = new Form1();

        public Nonameclass()
            {

            cnt = 0;

            mycounter = new System.Timers.Timer();
            mycounter.Interval = 1000;
            mycounter.Start();
            mycounter.Elapsed += mycounter_Tick;

        }

        private void mycounter_Tick(object source, System.Timers.ElapsedEventArgs e)
        {
            try
            {
                cnt = cnt + 1;
                frm.textBox1.Text = cnt.ToString();
            }
            catch (Exception ex)
            {
            }

        }
    }
}
 

Attachments

  • Test CSharp - Writting to WindowsForm textbox.zip
    69.2 KB · Views: 4

jmcilhinney

C# Forum Moderator
Staff member
Joined
Apr 23, 2011
Messages
3,903
Location
Sydney, Australia
Programming Experience
10+
There's a lot wrong there. Firstly, there's no use creating a new Form1 object inside your class because anything you do to that will have no effect on the existing instance. If I had a notebook and you wanted to write something on it, do you think that it would be useful to go and buy a new notebook of the same type and write on that? Of course not, so why should it work for forms?

Secondly, you're using a System.Timers.Timer and that will raise its Elapsed event on a background thread, which means that you cannot directly affect any controls because they are created on the UI thread. You'd have to either marshal a call to the UI thread, set the Timer's SynchronizingObject property or just using a System.Windows.Forms.Timer instead. If you know it's for a WinForms app, you may as well use the last option.

Finally, that class shouldn't even know that the form exists, never mind the TextBox. The proper way to do this is for that class to raise an event and then expose the data, either via a property or the event args, and then the form can handle the event, get the data and update its own TextBox. As a general rule, the only place you should ever be directly affecting a control is the form it is a child of. Here's an example of doing it the proper way, with data exposed in both ways:
C#:
public class DataAvailableEventArgs : EventArgs
{
    public int Number { get; }

    public DataAvailableEventArgs(int number)
    {
        this.Number = number;
    }
}
C#:
public class Thing
{
    private readonly Timer ticker = new Timer {Interval = 1000, Enabled = true};

    private readonly Random rng = new Random();

    public DateTime CurrentTime { get; private set; }

    public event EventHandler<DataAvailableEventArgs> DataAvailable;

    public Thing()
    {
        ticker.Tick += Ticker_Tick;
    }

    private void Ticker_Tick(object sender, System.EventArgs e)
    {
        CurrentTime = DateTime.Now;
        OnDataAvailable(new DataAvailableEventArgs(rng.Next()));
    }

    protected virtual void OnDataAvailable(DataAvailableEventArgs e)
    {
        DataAvailable?.Invoke(this, e);
    }
}
As you can see, when the internal Timer raises a Tick event, the Thing class raises its own DataAvailable event, making some data available via a property and some other data available via the event args. The form then handles that event and gets that data:
C#:
private readonly Thing something = new Thing();

private void Form1_Load(object sender, EventArgs e)
{
    something.DataAvailable += Something_DataAvailable;
}

private void Something_DataAvailable(object sender, DataAvailableEventArgs e)
{
    // Get data from a property.
    textBox1.Text = something.CurrentTime.ToString();

    // Get data from the event args.
    textBox2.Text = e.Number.ToString();
}
 
Top Bottom