Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Westi on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

ListBox - ValueMember problems 2

Status
Not open for further replies.

keyser456

IS-IT--Management
Nov 21, 2003
73
US
I add several objects of type MyListItem to the ItemCollection in my ListBox. MyListItem is a simple class containing an ID field (int) and a Name field (string), with corresponding properties. I set the ValueMember field of the ListBox to the &quot;ID&quot; property and the DisplayMember to the &quot;Name&quot; property of the ListItem objects. The ListBox displays the names just fine in the list, but when I select an item in the list and try to use the SelectedValue I'm getting <undefined value> rather than the proper ID value (int). When I cast the SelectedItem object to MyListItem to obtain the ID it works fine, but SelectedValue should do the same, shouldn't it?
 
If you talk about the ListBox as a control of the System.UI.Web.Controls then SelectedValue returns a string.
The SelectedValue of the ListBox control of the System.Windows.Forms returns an object containing the value of the member of the data source specified by the ValueMember property.
So you have to unbox the returned object.

-obislavu-

 
I'm using Windows Forms in this scenario. I AM trying to unbox the &quot;object&quot; but there is nothing to unbox. For instance I added the following debugging code:

if (this.lstBox.SelectedIndex != -1)
Console.WriteLine(&quot;SelectedValue = {0}&quot;, (int)this.lstBox.SelectedValue);

It comes back with:

An unhandled exception of type 'System.NullReferenceException' occurred in MDDB1.exe

Additional information: Object reference not set to an instance of an object.

I play around with the command window while the code is paused and it looks like this should work, and yet it doesn't.

? this.lstBox.ValueMember
&quot;ID&quot;
? this.lstBox.SelectedIndex
4
? this.lstBox.SelectedValue
<undefined value>
? (int)this.lstBox.SelectedValue
error: '(int)' cannot be performed on 'this.lstBox.SelectedValue'
? ((ListItem)this.lstBox.SelectedItem).ID
424

What am I doing wrong?
 
this.lstBox.SelectedValue returns an object of type as the ValueMember e.g.
If you say
this.lstBox.ValueMember = &quot;ShortName&quot;
that means that &quot;ShortName&quot; could be a column in a DataTable (datasource) with the name &quot;ShortName&quot; or something like you see in the example below using arraylist.

public class Province
{
private string myShortName ;
private string myLongName ;

public Province(string strLongName, string strShortName)
{

this.myShortName = strShortName;
this.myLongName = strLongName;
}

public string ShortName
{
get
{
return myShortName;
}
}

public string LongName
{

get
{
return myLongName ;
}
}

public override string ToString()
{
return this.ShortName + &quot; - &quot; + this.LongName;
}
}


Now in a form that contains the listBox1 control and a textBox1 control:

private void InitializeListBox()
{
ArrayList Provinces = new ArrayList() ;
Provinces.Add(new Province(&quot;Alberta&quot;, &quot;AB&quot;));
Provinces.Add(new Province(&quot;Columbie Britanique&quot;, &quot;CB&quot;)) ;
Provinces.Add(new Province(&quot;Quebec&quot;, &quot;Qc&quot;));
Provinces.Add(new Province(&quot;Ontario&quot;, &quot;ON&quot;)) ;
Provinces.Add(new Province(&quot;Manitoba&quot;, &quot;MN&quot;));
listBox1.DataSource = Provinces ;
listBox1.DisplayMember = &quot;LongName&quot; ;
listBox1.ValueMember = &quot;ShortName&quot; ;

}

private void listBox1_SelectedIndexChanged(object sender, System.EventArgs e)
{
if (listBox1.SelectedIndex != -1)
{
textBox1.Text = listBox1.SelectedValue.ToString();
}
}
Here listBox1.SelectedValue will be a type of &quot;string&quot; because when the ValueMember was set to &quot;ShortName&quot; this one is a PROPERTY of type of &quot;string&quot; as you can see in the Province class definition :
public string ShortName
{
get
{
return myShortName;
}
}
This was mandatory to be defined in order to set it as a ValueMember.

-obislavu-


 
obislavu - Thank you for your patience, however I believe I have everything set up almost exactly as you have described.

Here is my ListItem definition (I just noticed it's a struct instead of a class, but I've tried it both ways w/ no luck)

public struct ListItem
{
private int id;
private string name;

public ListItem(int inid, string inname)
{
this.id = inid;
this.name = inname;
}
public int ID
{
get{return this.id;}
}
public string Name
{
get{return this.name;}
}
}

Here is a section of code for adding items to the ListBox and setting its properties:

cmd.Connection.Open();
System.Data.SqlClient.SqlDataReader rdr = cmd.ExecuteReader();
int ID;
string str;
this.lstBox.BeginUpdate();
while (rdr.Read())
{
if (!rdr.IsDBNull(0))
{
ID = rdr.GetInt32(0);
}
else
{
ID = -1;
throw new System.Exception(&quot;Error: Cannot use null value&quot;);
}
if (!rdr.IsDBNull(1))
{
str = rdr.GetString(1);
}
else
{
str = &quot;&quot;;
}
this.lstBox.Items.Add(new ListItem(ID, str));
}
rdr.Close();
cmd.Connection.Close();
this.lstBox.EndUpdate();
this.lstBox.ValueMember = &quot;ID&quot;;
this.lstBox.DisplayMember = &quot;Name&quot;;

Everything works beautifully so far. The list fills, the correct names display, meaning the DisplayMember part is working fine but when an item is selected the SelectedValue does NOT refer to the ID Property of the ListItem.

The only thing that I can think of is that I don't have a DataSource defined. I am adding ListItems directly to the Items collection of the listbox. However, the DisplayMember is obviously able to use the &quot;Name&quot; property of the ListItems and I believe ValueMember should work in the same manner.
 
There is the problem.
You should set the DataSource to an object such as DataSet Type or Array type or derived from one of these. More generally DataSource should implement IList interface.
So change your code like here:
ArrayList MyItems = new ArrayList();
When reading one record fronm the databse create new ListItem and add it to the array list:

MyItems.Add(new ListItem(ID,str));

this.lstBox.DataSource = MyItems;
this.lstBox.ValueMember = &quot;ID&quot;;
this.lstBox.DisplayMember = &quot;Name&quot;;

private void lstBox_SelectedIndexChanged(object sender, System.EventArgs e)
{
if (lstBox.SelectedIndex != -1)
{
MessageBox.Show(lstBox.SelectedValue.ToString());
}
}


-obislavu-
 
In Windows Forms, for ListBox class, is there a method available to get the associated value to any specified item in the list?

There is a GetItemText method, but there is no GetItemValue. I don't know how to get the value.

I know there is a SelectedValue property. I want to be able to specify any item, not just the selected item.

Thanks.

 
In .net, the listbox items are their own values.

If you take a look at the docs, you'll see that listbox contains items of type Object. And since everything in .net ultimately inherits from Object, you can store anything in a listbox.

You'll want to override the ToString method to ensure that you can control what gets shown to the user in the listbox.

So, say that you want to store invoice information in the listbox. You'd create a class called InvoiceLB:
Code:
public class InvoiceLB
{
  public int InvoiceNumber;
  public string InvoiceName;

  public InvoiceLB()
  { }

  public InvoiceLB(int InvoiceNumber, string InvoiceName)
  {
    this.InvoiceNumber = InvoiceNumber;
    this.InvoiceName = InvoiceName;
  }

  public override string ToString()
  {
    return this.InvoiceName;
  }
}
And you'd add them to the list of items in the listbox:
Code:
InvoiceLB ilb1 = new InvoiceLB(1, "MegaWidget");
myForm.InvoiceList.Items.Add(ilb1);
ilb1 = new InvoiceLB(2, "FoozieWhatsit");
myForm.InvoiceList.Items.Add(ilb1);
When the user selects an item from the listbox, the SelectedItem will be your InvoiceLB object:
Code:
InvoiceLB selILB = myForm.InvoiceList.SelectedItem as InvoiceLB;
Console.Writeline(selILB.InvoiceNumber);
Chip H.

____________________________________________________________________
Click here to learn Ways to help with Tsunami Relief
If you want to get the best response to a question, please read FAQ222-2244 first
 
Using the above example where a listBox is bound to an ArrayList, it is clear that the listBox1 has the Items collection and that collection contains the objects of Province type.
These objects can be accessed by index or iterating the collection:
Code:
for (int i=0;i< listBox1.Items.Count;i++)
{
	Province prov = (Province)listBox1.Items[i];
	Object valmember= prov.ShortName;
}
To get the object in the listBox at a given idx index:
Code:
Object obj = listBox1.Itesm[idx];
Now, cast it to the type of the object that was added in the list:
Code:
Province prov = (Province)obj;
Object display = prov.LongName;
Object valmamber = prov.ShortName;
obislavu
 
I should have told you that I queried a db table and set the display member and value member of the listbox to the appropriate fields of the dataset (from the db query). You said that each item in the listbox is an object. In your example, they are of the type Province. In my case (listbox bound to a dataset), what is the type of my listbox items?

Dummy Lee
 
In fact display member and value member are columns of a DataTable.
The type of the object is
Code:
System.Data.DataRowView;
obislavu
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top