Solved

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

Posted on 2004-09-05
17
3,259 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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Why You Should Analyze Threat Actor TTPs

After years of analyzing threat actor behavior, it’s become clear that at any given time there are specific tactics, techniques, and procedures (TTPs) that are particularly prevalent. By analyzing and understanding these TTPs, you can dramatically enhance your security program.

 
LVL 2

Author Comment

by:gdbjohnson
Comment Utility
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
Comment Utility
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
Comment Utility
>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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
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
Comment Utility
Scratch that:

This will do:

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

Author Comment

by:gdbjohnson
Comment Utility
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

6 Surprising Benefits of Threat Intelligence

All sorts of threat intelligence is available on the web. Intelligence you can learn from, and use to anticipate and prepare for future attacks.

Join & Write a Comment

In order to hide the "ugly" records selectors (triangles) in the rowheaders, here are some suggestions. Microsoft doesn't have a direct method/property to do it. You can only hide the rowheader column. First solution, the easy way The first sol…
Introduction Hi all and welcome to my first article on Experts Exchange. A while ago, someone asked me if i could do some tutorials on object oriented programming. I decided to do them on C#. Now you may ask me, why's that? Well, one of the re…
This video gives you a great overview about bandwidth monitoring with SNMP and WMI with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're looking for how to monitor bandwidth using netflow or packet s…
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

763 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

6 Experts available now in Live!

Get 1:1 Help Now