Solved

How do I force a ListBox to Re-Draw / Re-Process the Items in its List?

Posted on 2004-09-05
17
3,260 Views
Last Modified: 2012-08-14
I have a listbox that I have built in the following way:

foreach (dsoDataSet.MyDataTableRow dr in dsDataSet.MyTable.Rows )
{
   lstDegree.Items.Add(new DegreeLst(dr.DegreeID, dr.Name));
}
lstDegree.DisplayMember = "DegreeName";
lstDegree.ValueMember = "DegreeID";
lstDegree.SelectedIndex = 0;
LoadDegree();


I have built a simple class to hold the DegreeID and the DegreeName (and description), so that I can keep track of the ID's underneath, while displaying a user friendly name to the user.

Unfortunately, the "DisplayMember" and "ValueMember" fields do not work unless the DataSource has been specified (is that correct?), so I have overridden the ToString() method of my class to return the "DegreeName".

This all works as expected, but I am having one small problem.
If I change the underlying string value of "DegreeName" like so:

((DegreeLst)lstDegree.SelectedItem).DegreeName = txtDegreeName.Text;

then the text in the ListBox does not update as expected, and I can't seem to find the method that will force a refresh of the text for the Items collection.

How do I force a ListBox to Re-Draw / Re-Process the Items in its List?

Thanks

gdbj
0
Comment
Question by:gdbjohnson
  • 8
  • 4
  • 3
  • +1
17 Comments
 
LVL 19

Expert Comment

by:drichards
ID: 11986783
You need to remove and insert.  For example:

   int idx = lstdegree.SelectedIndex;
   if ( idx >= 0 )
   {
      DegreeLst dl = (DegreeLst)lstDegree.SelectedItem;
      dl.DegreeName = txtDegreeName.Text;
      lstDegree.Items.RemoveAt(idx);
      istDegree.Items.Insert(idx, dl);
   }
0
 
LVL 19

Expert Comment

by:drichards
ID: 11986788
You should also do:

      lstDegree.SelectedIndex = idx;

or you will be back at the top of the list.
0
 
LVL 2

Author Comment

by:gdbjohnson
ID: 11996543
I had considered that that would be the surefire way to get it to work too, but I would have thought that, surely, there would be a technique/method provided to allow us to simply get the list item to update/refresh.

I figured that the Items list was just another way to create a databinding on the fly.  For example, I could build an ArrayList consisting of the same objects, and then set the ArrayList to the DataSource of the ListBox, with ValueMember and Display member set properly, and (although I haven't tried it), the list should update when the underlying values change...  at least this is the way databinding usually works and this is what I have read online.

I don't understand why there should be a difference.  You wouldn't happen to know, whould you?
0
 
LVL 7

Expert Comment

by:NipNFriar_Tuck
ID: 11997102
If you have the list box updated with the items that you want you can do

     lstDegree.Invalidate();
     lstDegree.Refresh();

To get the list box to redraw it's contents.
0
 
LVL 2

Author Comment

by:gdbjohnson
ID: 11997502
Excellent.  I will try that later on in the day.  I searched that intellisense list 3x (it's a very long list) and tried various promising-looking methods including refresh(), but to no avail.  

I missed that one: Invalidate().
0
 
LVL 2

Author Comment

by:gdbjohnson
ID: 12027173
well, no tacos for you, amigo.

The list redraws it self, as evidenced by a slight flicker, but the list item object does not update with the new value.  It's the darndest thing.  
This ListBox really loves that initial value, but it should realize that change is good.

I might go with just removing and re-adding the item, although this is very unsatisfactory.

G
0
 
LVL 19

Accepted Solution

by:
drichards earned 100 total points
ID: 12027257
According to the docs "When an object is being added to the ListBox, the control uses the text defined in the ToString method of the object unless a member name within the object is specified in the DisplayMember property".  This would say that the item control loads the string when the item is added to the ListBox and at no other time.  There is probably an internal property of the item control that stores the string as the item is added and it never gets reloaded.  Seems like a bad design.  You could always do owner-draw, I suppose, and reload the item string each time it is redrawn.
0
 
LVL 7

Assisted Solution

by:NipNFriar_Tuck
NipNFriar_Tuck earned 25 total points
ID: 12027713
Hmmm.... The way that I develop is to keep the datasource, so I would have a strongly typed collection that I am using and then displaying with the list box.  Then when something changed on the data I change the collection and then reattach it to the list box by setting the DataSource.  Then in the list box I can set the DisplayMember and the ValueMember... This may be a way to go for you also.
0
Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

 
LVL 2

Author Comment

by:gdbjohnson
ID: 12027953
drichards:

> unless a member name within the object is specified in the DisplayMember property
This is incorrect - depending on how you build the list.  
If you add the items using
ListBox.Items.Add (new MyObject(value, display) )
then, contrary to documentation which I've read too, DisplayMember and Valuemember do not seem to work.  This has been my experience.  I had to override ToString() to get the display property to display, otherwise it just displayed the name of my Object, which is what a default ToString() returns, I believe.

If, however, you add the items to an ArrayList first, and then set the DataSource property with this ArrayList, then these properties work.

But, either way you get the values into the list, the dsiplayed text does not update with changes.  I've tried it both ways.  Looking at the ListBox object in Locals in debugging, I searched every property for the displayed text to see where it might be stored, and it seems completely hidden: I could only find the updated string that I wanted displayed.

>Seems like a bad design.

I would have to agree.  Regardless of the internal techniques for getting the string to display, there should not be a disconnect between the objects building the list, and the list that gets displayed.  The List should behave exactly like DataBinding as far as I'm concerned.  At least they could provide a method for refreshing the list, which is what I was hoping to get from this discussion.

What I am doing now is clearing the list, and then re-adding each list item during a Text_Changed event.  This is OK, because the list will always be short.  This will be a problem for a long list, or a really slow computer.

-g
0
 
LVL 7

Expert Comment

by:NipNFriar_Tuck
ID: 12028494
G, if you did not use a strongly typed list/collection then the DisplayMember and ValueMemeber will not work.
0
 
LVL 2

Author Comment

by:gdbjohnson
ID: 12029769
>strongly typed list/collection

I suppose I don't know exactly what this means. I'm new to C#.

Doing an Items.Add (new Object()) cannot create a strongly-typed list?

I didn't think there was much of a functional difference between:
----
For x = 0; x < 10; x++
   ListBox.Items.Add (new Object() )
----

and
---
arr=  new ArrayList()
for x = 1 to 10
   arr.Add(new Object())
ListBox.DataSource = arr
----

to create the list?

-g

0
 
LVL 7

Expert Comment

by:NipNFriar_Tuck
ID: 12031218
Correct.... That creates object which do not have the properties et el...

If when you access an element you get an object then that is NOT a strongly typed list as that could be any object, which may not have the properties that you assigned to the DisplayMember or the ValueMember.

You could do Items.Add( new myClass() ) but why not do:

public class MyClass {
    // Class stuff
}

public class MyClasses : CollectionBase {
   // See CollectionBase for implementation
}

and then

MyClasses mcs = new MyClasses();
mcs.Add( new MyClass() );
mcs.Add( new MyClass() );
mcs.Add( new MyClass() );
mcs.Add( new MyClass() );
mcs.Add( new MyClass() );
mcs.Add( new MyClass() );
mcs.Add( new MyClass() );
mcs.Add( new MyClass() );
mcs.Add( new MyClass() );
ListBox.DataSource = mcs;


Of course MyClass should be filled out! but you get the point...
0
 
LVL 2

Author Comment

by:gdbjohnson
ID: 12043809
I used the ArrayList technique and it does work:
---
arr=  new ArrayList()
for x = 1 to 10
   arr.Add(new Object())
ListBox.DataSource = arr
---

But, I didn't need to override a CollectionBase class.  My ListBox allowed me to use Display and ValueMember to access fields in my Object class.  But perhaps this is a poor technique, so I will take a look at making a more robust list.
0
 
LVL 2

Author Comment

by:gdbjohnson
ID: 12043891
drichards:

It seems that after all the discussion, we end up back at the top, where your first suggestion was the solution.

G
0
 
LVL 2

Expert Comment

by:Cheney
ID: 12344881
Heres a hack for you:

Whenever you update the data in your object, run this code to reflect the changes in the listbox (assuming you have overridden the ToString method in your class)

int index = accountsListBox.SelectedIndex;
listBox.Items[index] = myArrayOfObjects[index];
listBox.SelectedIndex = index;

:D
0
 
LVL 2

Expert Comment

by:Cheney
ID: 12344900
Scratch that:

This will do:

listBox.Items[indexOfChangedObject] = myArrayOfObjects[indexOfChangedObject];
0
 
LVL 2

Author Comment

by:gdbjohnson
ID: 12347164
so you don't need to actually do the remove... it's more just replacing the object that index points to, and it refreshes the display.  Cool.  Thanks.
0

Featured Post

Is Your Active Directory as Secure as You Think?

More than 75% of all records are compromised because of the loss or theft of a privileged credential. Experts have been exploring Active Directory infrastructure to identify key threats and establish best practices for keeping data safe. Attend this month’s webinar to learn more.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Real-time is more about the business, not the technology. In day-to-day life, to make real-time decisions like buying or investing, business needs the latest information(e.g. Gold Rate/Stock Rate). Unlike traditional days, you need not wait for a fe…
This Micro Tutorial will give you a basic overview how to record your screen with Microsoft Expression Encoder. This program is still free and open for the public to download. This will be demonstrated using Microsoft Expression Encoder 4.
Both in life and business – not all partnerships are created equal. As the demand for cloud services increases, so do the number of self-proclaimed cloud partners. Asking the right questions up front in the partnership, will enable both parties …

910 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

23 Experts available now in Live!

Get 1:1 Help Now