Home > Net >  C# Windows Form Text is not updating
C# Windows Form Text is not updating

Time:08-24

I'm new in programming with windows forms. I created a server and a client, where the server is sending data to the client/clients in a byte array and the client is decoding it and updating his textboxes with the information it received.

My problem: it doesn't updates the actual form.

by clicking the button on the Form (ClientForm) a methode from another class is called which connects it to the server, and receives the data. this data is then decoded (see below) and send to the Form Class through a String array where i want to update the textboxes.

here is some code that visualizes it:

EDIT: I changed the example code so there wont be a unknown class

clientform:

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

        private void btnConnect_Click(object sender, EventArgs e)
        {
            Experiment ex = new Experiment();
            ex.Hello();
        }

        // this methode is called outside of this class, see below
        public void SendDecodedData(List<String> data)
        {
          textbox1.Text = data[0];
          textbox2.Text = data[1];
          textbox3.Text = data[2];
        }
    }


By stopping the code at some of those changes, I can see that the textbox.Text is actually updated, however, it is not showing on the form.

other class

internal class Experiment
    {
        ClientForm client = new ClientForm();
        public void Hello()
        {
            List<String> list = new List<String>()
                    { "text1", "text2", "text3"};
            client.SendDecodedData(list);
        }

    }

If I call the methode SendDecodedData inside the form, for example instead of connecting:

private void btnConnect_Click(object sender, EventArgs e)
        {
            List<String> list = new List<String>()
                    { "text1", "text2", "text3", "text4"};
            SendDecodedData(list);
            
        }

it does work. There is some kind of rule that i dont know and cant find on the internet, that says how to change textboxes outside of the formclass.

Can anybody help me?

If the question isn't clearly stated or I forgot important informations, please comment and let me know! I dont ask a lot on here.

The problem is similar to the one linked below, but no answers helped unfortunately.

C# TextBox Control Not Updating With New Text

CodePudding user response:

You are creating a new form instance inside DecodeReceivedData to set the text boxes on, but this won't be the same form instance that is being shown to the user which is why those changes you make are not visible.

Rather than creating a new ClientForm inside DecodeReceivedData, you can simply pass that List<string> back and have the form itself update the text boxes.

Your Experiment class would then look like this (note the change in the Hello method to return back a List<string>):

internal class Experiment
{
    public List<string> Hello()
    {
        List<String> list = new List<String>()
                { "text1", "text2", "text3"};
        return list;
    }
}

Now when you create your Expermiment instance and call the Hello method, you'd store that returned list and use the items in it to update your form's text boxes:

private void btnConnect_Click(object sender, EventArgs e)
{
    Experiment ex = new Experiment();
    List<string> data = ex.Hello();
    
    textbox1.Text = data[0];
    textbox2.Text = data[1];
    textbox3.Text = data[2];
}

The original question mentioned connecting to a server to request the information you need to show. Assuming that is using something like HttpClient to issue those requests, you can use async and await to keep the code pretty much the same:

internal class Experiment
{
    public Task<List<string>> Hello()
    {
        //You'd want to create a single instance of HttpClient and re-use it in a real application
        using(var httpClient = new HttpClient())
        {
            var result = new List<string>();
            var response = await httpClient.GetStringAsync("https://your-server");

            //Do something with response to get your list 
            
            return result;
        }
    }
}

//Be aware there are some gotcha's with async void around handling
//errors. Using it on event handlers is the only time you'd ever need
//to do this
private async void btnConnect_Click(object sender, EventArgs e)
{
    Experiment ex = new Experiment();
    List<string> data = await ex.Hello();

    textbox1.Text = data[0];
    textbox2.Text = data[1];
    textbox3.Text = data[2];
}

And your

CodePudding user response:

You are creating a new instance of the form and not using the one that already exists. It's like you have two bank accounts and you're depositing in one and wondering why the balance of the other hasn't changed.

There are two simple ways to solve this.

The first is pass the reference to the current form:

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

    private void btnConnect_Click(object sender, EventArgs e)
    {
        Experiment ex = new Experiment();
        ex.Hello(this);
    }

    public void SendDecodedData(List<String> data)
    {
        textbox1.Text = data[0];
        textbox2.Text = data[1];
        textbox3.Text = data[2];
    }
}

internal class Experiment
{
    public void Hello(ClientForm client)
    {
        List<String> list = new List<String>()
                    { "text1", "text2", "text3"};
        client.SendDecodedData(list);
    }
}

But that's not ideal because it makes a dependency inside the class Experiment.

It's better to not pass the form around, instead the data:

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

    private void btnConnect_Click(object sender, EventArgs e)
    {
        Experiment ex = new Experiment();
        this.SendDecodedData(ex.Hello());
    }

    private void SendDecodedData(List<String> data)
    {
        textbox1.Text = data[0];
        textbox2.Text = data[1];
        textbox3.Text = data[2];
    }
}

internal class Experiment
{
    public List<String> Hello()
    {
        List<String> list = new List<String>() { "text1", "text2", "text3"};
        return list;
    }
}

Option 3 - use an event:

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

    private void btnConnect_Click(object sender, EventArgs e)
    {
        Experiment ex = new Experiment();
        ex.HelloData  = (s, data) => this.SendDecodedData(data);
        ex.Hello();
    }

    private void SendDecodedData(List<String> data)
    {
        textbox1.Text = data[0];
        textbox2.Text = data[1];
        textbox3.Text = data[2];
    }
}

internal class Experiment
{
    public event EventHandler<List<String>> HelloData;
    public void Hello()
    {
        List<String> list = new List<String>() { "text1", "text2", "text3"};
        this.HelloData?.Invoke(this, list);
    }
}

This final approach avoids the need for the class Experiment to know anything about the form - which is good. And it allows the form not the be the one that calls Hello.


Option 4 - async/await:

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

    private async void btnConnect_Click(object sender, EventArgs e)
    {
        Experiment ex = new Experiment();
        this.SendDecodedData(await ex.HelloAsync());
    }

    private void SendDecodedData(List<String> data)
    {
        textbox1.Text = data[0];
        textbox2.Text = data[1];
        textbox3.Text = data[2];
    }
}

internal class Experiment
{
    public Task<List<String>> HelloAsync()
    {
        return Task.Run(() =>
        {
            List<String> result = new List<String>() { "text1", "text2", "text3" };
            return result;
        });
    }
}

In the comments discussion you say that the call to Hello prevents the button click event from completing then you need use async/await to prevent your UI locking up.

CodePudding user response:

Why not just change the ClientForm constructor to be able to receive data?

        public ClientForm(List<String> list)
        {
            InitializeComponent();
            if (list != null)
            {
                 //do stuff...
                 //save to private var like "List<String> pvtList"
            }
            else
            {
                 //use Enigmativity sugestion
            }
        }
  • Related