blah blah blah is here! blah blah » Close

up1down
link

Is it possible to bind a List<T> to a listbox control? I see examples that seem to do this by simply assigning the listbox's datasource property to the List<T>. However, I don't seem to have the option of a datasource property.

Here is what I'd like to do. I've got a List<UserListItems>. A UserListItem consists of the fields Name, Phone, Email, Level. On the UI I have a listbox control which will list all users by name. When a user is selected from the listbox, 4 text boxes are populated. These textboxes are associated with the fields in UserListItem.

Ideally these would all be bound such that the user can modify a text box field and the associated List<T> item is updated.

EDIT:

Adding the specific list that I want to bind.

//EXAMPLE BIND IN WPF FORM

ListUsers.DisplayMemberPath = "Name";
ListUsers.ListUsers.DataContext = device.UsersTable;

//OBJECT CREATION FROM WITHIN DEVICE CLASS

UsersTable = new DeviceDataTable<UserListItem>();

//INTERFACE AND EXTENDED LIST

interface IDeviceTableItem
{
byte[] ToByteArray();

byte UID
{
set;
get;
}

int RowSize
{
set;
get;
}

}

class DeviceDataTable<T> : IEnumerable<T> where T : IDeviceTableItem
{
private List<T> table = new List<T>();

public T this[int pos]
{
get
{
return table[pos];
}
set
{
table[pos] = value;
}
}

public void AddRow(T r)
{
table.Add(r);
this.UpdateID();
}

public void RemoveRow(Int32 i)
{
table.RemoveAt(i);
this.UpdateID();
}

private void UpdateID()
{
byte i = 0;
foreach (T t in table)
{
t.UID = i++;
}
}

private byte[] ToByteArray()
{
byte[] tableArray=new byte[table.Count];

return tableArray;
}




IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return table.GetEnumerator();
}


IEnumerator IEnumerable.GetEnumerator()
{
return table.GetEnumerator();
}

}

//HERE IS ONE POSSIBLE DEVICE TABLE

class UserListItem : IDeviceTableItem
{

public const int FIELD_SIZE_UID = 1;
public const int FIELD_SIZE_NAME = 32;
public const int FIELD_SIZE_CELL = 16;
public const int FIELD_SIZE_EMAIL = 64;
public const int FIELD_SIZE_LEVEL = 1;

private const int FIELD_OFFSET_UID = 0;
private const int FIELD_OFFSET_NAME = FIELD_OFFSET_UID + FIELD_SIZE_UID;
private const int FIELD_OFFSET_CELL = FIELD_OFFSET_NAME + FIELD_SIZE_NAME;
private const int FIELD_OFFSET_EMAIL = FIELD_OFFSET_CELL + FIELD_SIZE_CELL;
private const int FIELD_OFFSET_LEVEL = FIELD_OFFSET_EMAIL + FIELD_SIZE_EMAIL;

private int ROW_SIZE = FIELD_SIZE_UID + FIELD_SIZE_NAME + FIELD_SIZE_CELL + FIELD_SIZE_EMAIL + FIELD_SIZE_LEVEL;

public enum AccessLevels : byte
{
Admin = 1,
Ordinary = 2
}

private byte uid;
public string Name;
public string CellPhone;
public string Email;
public AccessLevels Level;

public byte UID
{
set
{
this.uid = value;
}
get
{
return this.uid;
}
}

public int RowSize
{
set
{
}
get
{
return this.ROW_SIZE;
}
}

public UserListItem(string name, string cellphone, string email, AccessLevels level)
{
this.Name = name;
this.CellPhone = cellphone;
this.Email = email;
this.Level = level;
}

public byte[] ToByteArray()
{
byte[] rowArray= new byte[ROW_SIZE];

//Construct byte array representing table row
rowArray[FIELD_OFFSET_UID] = UID;
System.Text.ASCIIEncoding encoding = new ASCIIEncoding();
encoding.GetBytes(this.Name.PadRight(FIELD_SIZE_NAME).Substring(0, FIELD_SIZE_NAME - 1)).CopyTo(rowArray, FIELD_OFFSET_NAME);
encoding.GetBytes(this.CellPhone.PadRight(FIELD_SIZE_CELL).Substring(0, FIELD_SIZE_CELL - 1)).CopyTo(rowArray, FIELD_OFFSET_CELL);
encoding.GetBytes(this.Email.PadRight(FIELD_SIZE_EMAIL).Substring(0, FIELD_SIZE_EMAIL - 1)).CopyTo(rowArray, FIELD_OFFSET_EMAIL);
rowArray[FIELD_OFFSET_LEVEL] = (byte)this.Level;
return rowArray;
}

}

last answered 2 years ago

1 answers

link

What I'd do is something like this:

private List<UserListItem> users; 

private void Form1_Load(object sender, EventArgs e)
{
users = new List<UserListItem>();
// populate users
listBox1.DataSource = users;
listBox1.DisplayMember = "Name";
listBox1.SelectedIndex = 0;
}

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
{
UserListItem user = users[listBox1.SelectedIndex];
textBox1.Text = user.Phone;
textBox2.Text = user.Email;
textBox3.Text = user.Level;
}

private void textBox1_Leave(object sender, EventArgs e)
{
UserListItem user = users[listBox1.SelectedIndex];
textBox1.Text = textBox1.Text.Trim();
if (user.Phone != textBox1.Text)
{
user.Phone = textBox1.Text;
}
}

private void textBox2_Leave(object sender, EventArgs e)
{
UserListItem user = users[listBox1.SelectedIndex];
textBox2.Text = textBox2.Text.Trim();
if (user.Email != textBox2.Text)
{
user.Email = textBox2.Text;
}
}

private void textBox3_Leave(object sender, EventArgs e)
{
UserListItem user = users[listBox1.SelectedIndex];
textBox3.Text = textBox3.Text.Trim();
if (user.Level != textBox3.Text)
{
user.Level = textBox3.Text;
}
}


EDIT - WPF version of the above

private List<UserListItem> users; 

private void Window_Loaded(object sender, RoutedEventArgs e)
{
users = new List<UserListItem>();
// populate users
listBox1.ItemsSource = users;
listBox1.DisplayMemberPath = "Name";
listBox1.SelectedIndex = 0;
}

private void listBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
UserListItem user = users[listBox1.SelectedIndex];
textBox1.Text = user.Phone;
textBox2.Text = user.Email;
textBox3.Text = user.Level;
}

private void textBox1_LostFocus(object sender, RoutedEventArgs e)
{
UserListItem user = users[listBox1.SelectedIndex];
textBox1.Text = textBox1.Text.Trim();
if (user.Phone != textBox1.Text)
{
user.Phone = textBox1.Text;
}
}

private void textBox2_LostFocus(object sender, RoutedEventArgs e)
{
UserListItem user = users[listBox1.SelectedIndex];
textBox2.Text = textBox2.Text.Trim();
if (user.Email != textBox2.Text)
{
user.Email = textBox2.Text;
}
}

private void textBox3_LostFocus(object sender, RoutedEventArgs e)
{
UserListItem user = users[listBox1.SelectedIndex];
textBox3.Text = textBox3.Text.Trim();
if (user.Level != textBox3.Text)
{
user.Level = textBox3.Text;
}
}

eeboy
499

I don't seem to have a DataSource property, or a DisplayMember property. I have DataContext and DisplayMemberPath. Thoughts?

eeboy
499

It seems that the properties are different because I am using WPF?? Not sure about that statement but that's what I gather. Anyways, after much digging I found that I need to set ItemsSource=users as well as DataContext=users. I've done this but I still have issues. Suggestions?

vulpes
17279

I've editied my answer to include the equivalent code in WPF.

eeboy
499

Thanks Vulpes! I am almost there I believe. I was able to take your example and get it to work but I am having trouble binding a specific list. I've edited my original post so that it formats nicely. Any thoughts as to why a simple list would work and this will not?

eeboy
499

FYI, when I bind the data (ex: Device.UsersTable ) it doesn't generate an exception or anything... simply no data shows in the listbox.

vulpes
17279

The problem is that Name in the UserListItem class needs to a public property rather than a field. Also the ListUsers.ItemsSource property needs to be set to device.UsersTable. I wouldn't bother setting the DataContext property.

eeboy
499

Almost there :). I changed the Name field to a property (public string Name{set;get;}). Data is now bound to the listbox but, the Name does not show. The list items in the box are simply blank. Now if I use UID as the DisplayMemberPath instead of Name, the number appears in the listbox. They are both properties of the same list. The property Name is definitely returning a string representing the users name. Thoughts?

eeboy
499

I got it to work... I was doing something silly. Thanks again vulpes!

salman
510

eeboy, why not mark the question as answered?

Feedback