Link to home
Start Free TrialLog in
Avatar of grokuk
grokuk

asked on

DataBinding an ArrayList to a ListBox and updating

Hi,

I have a ListBox which is bound to an ArrayList like so:

ArrayList *JumpPoints = new ArrayList();
ListBox *lbBeacons = new ListBox();

...etc...

lbBeacons->DataSource = JumpPoints;
lbBeacons->DisplayMember =S"BeaconString";

And all works fine until the ArrayList changes but the ListBox doesn't refresh in any way that reflects the changes. I have looked around and come across CurrencyManagers/BindingManagers but can find no coherent examples in VC++ that cover what I need.

Which is the best way to go to achieve this? Can anyone give a clear code example in VC++?

Many thanks.
Avatar of nonubik
nonubik

When the DataSource property is set, a user cannot modify the items collection.

I think you'll need to re set the DataSource
Avatar of grokuk

ASKER

I've tried reassigning the DataSource to zero and then back again to the ArrayList, but no improvement.
Have you tried to call DataBind() ?
ASKER CERTIFIED SOLUTION
Avatar of Svetlin_Panayotov
Svetlin_Panayotov

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
what i usually do is define a function which is called whenever the listbox needs to be updated...
inside this function i define and fill the arraylist, and bind it to the list box.

because the arraylist only exists in this local scope, every time this function is called the listbox is updated accordingly

i also include code at the beginning and end of the function which preserves the selected index - so if the data is refreshed on a timer, the user doesnt get interrupted.

void Reload_Data()
{

   // store selected index
   int index = this->Listbox->SelectedIndex;

   // create arraylist
   ArrayList * data = new ArrayList();

   // fill arraylist with relevant information
   // ...

   // bind arraylist to listbox
   this->Listbox->ValueMember = S"ID";
   this->Listbox->DisplayMember = S"Name";
   this->Listbox->DataSource = data;

   // restore selected index
   this->Listbox->SelectedIndex = index;
}

if you need to preserve your existing arraylist, you could pass it to this function like this

void Reload_Data(ArrayList * data)
{
    // ...
}

then call it as...
Reload_Data(JumpPoints);

when you call the function, your exsiting arraylist will be copied to a new one called 'data' which will only exist in the local scope, and the function will behave as expected

hope this helps
sorry forgot to mention - if you define the function with parameters (ArrayList * data) then obviously you must remove the ArrayList definition inside the function or you will get a compiler error !

I've run through the same problem with the difference that I program in C#.
But the solution should be the same.

Here is what I did....


ArrayList *JumpPoints = new ArrayList();
ListBox *lbBeacons = new ListBox();
lbBeacons->DataSource = JumpPoints;
lbBeacons->DisplayMember =S"BeaconString";

/****************whatever changes your arraylist*******************/
/*************************************************/

/*****************refreshing!!!! ************/
// Unbind the grid
lbBeacons->DataSource = null;
// Bind the grid
lbBeacons->DataSource = JumpPoints;
// This will refresh the currency manager.....
CurrencyManager currencymanager = (CurrencyManager)lbBeacons->BindingContext[JumpPoints];
currencymanager->Refresh();
/*****************finish refreshing!!!! ************/


Hope this works for you.......
Fernando de la Garza

Avatar of grokuk

ASKER

Thanks to those who've answered, but I'm still looking for a working VC++ (.NET) example.

Setting the DataSource to NULL and then back to the ArrayList does almost work, but it leaves a number of 'empty' items in the ListBox (despite reassigning the Display and Value Members).

The CurrencyManager approach of Fernando looks like the right sort of thing, but C++ handles the BindingContext in a rather different way to C#. Or at least, I can't find any equivalent to the lbBeacons->BindContect[JumpPoints] indirection that works. Maybe I'm missing something obvious?

Still searching....

i think you will find my method shown above works just fine. i have millions of listboxes, comboboxes and datagrids in my applications, which all use that method.

to re-iterate - define and fill the arraylist within a function. bind the arraylist to the listbox in the same function. whenever you want to update the listbox, simply call the function. because the arraylist is in local scope to that function, every time you call it the listbox sees a 'new' arraylist, and updates itself with the new data.

and of course, every time the list is refreshed, the previous arraylist no longer has any references to it, and so the garbage collector will deal with it accordingly
Avatar of grokuk

ASKER

Thanks Statick but I was hoping to find a solution that avoided re-iterating through the full list each time.

It turns out that I owe an apology to Svetlin_Panayotov as his solution does in fact work perfectly if you also reassign the DisplayMember as well as the DataSource.

In Short:

lbBeacons->DataSource = NULL;
lbBeacons->DataSource = JumpPoints;
lbBeacons->DisplayMember =S"BeaconString";

Does the trick.