I've got a class of users with some properties like name, age, gender and message and so I have a form that in it some text boxes created dynamically for each property of each user and I bind each textbox to appropriate properties.
When the users connect to my program and change their properties the text boxes don't change.
This is my user class:
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace binding_network
{
class user : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name != value)
{
_name = value;
NotifyPropertyChanged();
}
}
}
private int _age;
public int Age
{
get { return _age; }
set
{
if (_age != value)
{
_age = value;
NotifyPropertyChanged();
}
}
}
private string _message;
public string Message
{
get { return _message; }
set
{
if (_message != value)
{
_message = value;
NotifyPropertyChanged();
}
}
}
private string _gender;
public string Gender
{
get { return _gender; }
set
{
if (true)
{
_gender = value;
NotifyPropertyChanged();
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
and this is my form code:
public partial class Form1 : Form
{
private BindingSource userBindingSource = new BindingSource();
BindingList<user> userList = new BindingList<user>();
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
///some code to create textboxes dynamically....
txtName.DataBindings.Clear();
txtName.DataBindings.Add("text", userBindingSource[userIndex], "name");
txtAge.DataBindings.Clear();
txtAge.DataBindings.Add("text", userBindingSource[userIndex], "age");
txtGender.DataBindings.Clear();
txtGender.DataBindings.Add("text", userBindingSource[userIndex], "gender");
txtMessage.DataBindings.Clear();
txtMessage.DataBindings.Add("text", userBindingSource[userIndex], "message");
}
}
And by this method, I receive the data by network
private void GetMessage(object obj)
{
user user1 = (user)obj;
try
{
while (true)
{
byte[] buffer = new byte[1024];
int rec = user1.SocketClient.Receive(buffer, 0, buffer.Length, 0);
Array.Resize(ref buffer, rec);
if (rec > 0)
{
user1.Name = BitConverter.ToString(buffer, 0);
user1.Gender = BitConverter.ToString(buffer, 80);
user1.Age = BitConverter.ToInt32(buffer, 96);
user1.Message = BitConverter.ToString(buffer, 160);
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
}
But after receiving the data the textboxes don't refresh
A lot of code appears to be missing, but here's a few things...
The userBindingSource
hasn't been connected to userList
.
The binding propertyName
and dataMember
parameters have incorrect casing.
The userIndex
isn't defined.
Even if it were, binding to userBindingSource[userIndex]
doesn't allow navigation of the source (maybe you're fine with that).
So let's fix those:
public partial class Form1 : Form
{
private BindingSource userBindingSource = new BindingSource();
BindingList<user> userList = new BindingList<user>();
int userIndex = 0;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
userBindingSource.DataSource = userList;
userIndex = userBindingSource.Position;
///some code to create textboxes dynamically....
txtName.DataBindings.Clear();
txtName.DataBindings.Add("Text", userBindingSource, "Name");
txtAge.DataBindings.Clear();
txtAge.DataBindings.Add("Text", userBindingSource, "Age");
txtGender.DataBindings.Clear();
txtGender.DataBindings.Add("Text", userBindingSource, "Gender");
txtMessage.DataBindings.Clear();
txtMessage.DataBindings.Add("Text", userBindingSource, "Message");
}
}
Assuming that userList
has been populated, you may now navigate the userBindingSource
like this:
// However you're tracking userIndex, or maybe...
// userIndex = userList.IndexOf(user1);
userBindingSource.Position = userIndex;
Or any of these:
userBindingSource.MoveFirst();
userBindingSource.MovePrevious();
userBindingSource.MoveNext();
userBindingSource.MoveLast();
And finally, remove the infinite while (true)
loop in GetMessage
.
At this point, if your data is correctly received and parsed, your TextBox
controls should update.
Edit...
So you're multi-threading this, which is great.
Now we have to make sure all operations that result in a UI change are done on the proper thread.
Lets do this (assuming GetMessage
is defined inside the Form
class):
if (rec > 0)
{
var name = BitConverter.ToString(buffer, 0);
var gender = BitConverter.ToString(buffer, 80);
var age = BitConverter.ToInt32(buffer, 96);
var message = BitConverter.ToString(buffer, 160);
this.Invoke(new Action(() =>
{
user1.Name = name;
user1.Gender = gender;
user1.Age = age;
user1.Message = message;
}));
}
And this:
catch (Exception ex)
{
this.Invoke(new Action(() => MessageBox.Show(ex.ToString())));
}
And binding source navigation (if on a different thread):
this.Invoke(new Action(() => userBindingSource.Position = userIndex));
You may also look into using the BeginInvoke
method.