3rd party dual listbox control

D

Dave

Hi all,

After unsuccessfully trying to make my own dual listbox control out of
arraylists, I decided to look for a 3rd party control. I've looked for over
a week now and can't find anything but ASP.Net stuff when I need a Windows
Form control. I've seen dual listbox populators in countless Windows
applications, and have seen them run very fast, so I figured this would be
extremely popular.

Here's how it should work:
1. Data from an arraylist of objects is passed to the control.
2. The control populates a listbox on the right with this data (displaying
what column I want - say "StateNames" being displayed and "StateID" and
"StateAbbrev" and "Population" or any number of extra information from the
object that can be tracked with it).
3. The user makes 1 or more selections (multi-selection is optional, but
would be nice) and clicks on an "Add" or "<" button to send the selection(s)
to the left hand listbox.
The user may also "Remove" selections from the left hand listbox.
4. The items in the lefthand listbox are available as an arraylist for
further processing.

Sound simple?
It should be, but there are no examples anywhere of this being done with
arraylists, I've "googled", "webcrawled", etc for the last 10 days with no
luck (I have code doing this with datatables, yes, but I need it to be done
with arraylists - which has proved elusive).

Any ideas of where to start looking?

TIA
Dave
 
A

alejandro lapeyre

What is so difficult in writing this control?

insert one lisbox
insert the buttons
insert other listbox

fill the first listbox

create an empty arraylist

when the user clicks the move here button
get the item using the listbox.selectedindex
remove from the collection, and the listbox.items
add it to the other collection and to the other listbox

I am missing something?

Alejandro Lapeyre
 
M

MCDave

The first listbox cannot be updated directly as it is bound by the
arraylist.
So I remove an item from the arraylist that is tied to the first listbox,
but because the listbox is bound, I can't simply remove an item directly
from the listbox (if I try to remove anything directly from the listbox, I
get an error that basically says it is already bound - catch 22).

In other words:
say the bound listbox is called "lstRegionNames" and it is bound to the
arraylist "alRegionNames"


Private alRegionNames As New ArrayList
Private alSelectedRegionNames As New ArrayList

Private Sub form4_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
loadDBRegionNames()

End Sub


Private Sub loadDBRegionNames()

alRegionNames = SalesRegionsDB.GetRegionNamesActiveAL

'the first listbox bound to the arraylist
lstRegionNames.DisplayMember = "reg_name"
lstRegionNames.ValueMember = "reg_idx"
lstRegionNames.DataSource = alRegionNames

' the second listbox -
lstSelectedRegionNames.DisplayMember = "reg_name"
lstSelectedRegionNames.ValueMember = "reg_idx"

End Sub


Private Sub Add() 'called when clicking the Add button

If lstRegionNames.SelectedIndex < 0 Then Return 'if nothing selected,
exit sub
Dim sr As New SalesRegionDD 'the object which contains "reg_idx" and
"reg_name"
sr = lstRegionNames.SelectedItem
Me.lstSelectedRegionNames.Items.Add(sr) 'add the object to the second
listbox - this works fine

Me.alRegionNames.RemoveAt(lstRegionNames.SelectedIndex) 'remove that object
from the arraylist - this works fine- I verified this by looping through the
objects in "alRegionNames" - the object was indeed removed from the
arraylist

'an attempt at refreshing the first listbox by re-binding it to the
arraylist - this does not refresh "lstRegionNames"
Me.lstRegionNames.DataSource = Me.alRegionNames

End Sub


I had done this with a datatable and removing an item from the datatable
removes it from the bound listbox automatically.
Doing the exact same thing with an arraylist does not work, though.

I don't know how to proceed or what else needs to be done to be able to
remove the item from "lstRegionNames"
 
M

MCDave

When I say a bound listbox cannot be updated, I mean that I get the
following error:

"An unhandled exception of type 'System.ArgumentException' occurred in
system.windows.forms.dll
Additional information: Cannot modify the Items collection when the
DataSource property is set."

It appears there is a bug that prevents updating of a listbox from an
arraylist (when the arraylist is bound to the listbox).
 
A

alejandro lapeyre

Do not attach it to the DataSource property.

Simply fill the ListBox with the ArrayList contents.

Alejandro Lapeyre
 
M

MCDave

I did figure out a workaround that basically sets the datasource to the
clone of the original list as in the following:

Private alRegionNames As New ArrayList


Private Sub form4_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
loadDBRegionNames()

End Sub

Private Sub loadDBRegionNames()
alRegionNames = SalesRegionsDB.GetRegionNamesActiveAL

'the right hand box
lstRegionNames.DisplayMember = "reg_name"
lstRegionNames.ValueMember = "reg_idx"
lstRegionNames.DataSource = alRegionNames

End Sub

'sub called by add button click event
Private Sub Add()

Dim sindex As Integer = Me.lstRegionNames.SelectedIndex
If sindex < 0 Then Return

Dim sr As New SalesRegionDD
sr = Me.lstRegionNames.SelectedItem

Dim itemcount As Integer = Me.lstRegionNames.Items.Count

Me.lstSelectedRegionNames.Items.Add(sr) 'this is another listbox
that is not bound

Me.lstRegionNames.SelectedIndex = -1
Me.alRegionNames.RemoveAt(sindex)

' I put this test in to see if there is only 1 item left in the
source listbox, if so,
' set the datasource to nothing or else there will be a very
noticeable delay for the ' last item to pass over to the left box
If itemcount = 1 Then
Me.lstRegionNames.DataSource = Nothing
Else
Me.lstRegionNames.DisplayMember = "reg_name"
Me.lstRegionNames.ValueMember = "reg_idx"
Me.lstRegionNames.DataSource = Me.alRegionNames.Clone
' if you use the clone, then you don't have to set the datasource to
nothing first

End If


End Sub


However, my solution is not very elegant (and probably slow) and the ListBox
bugs will probably be remedied in DotNet 2.0.

I'll probably just do your solution and keep track of both the listbox and
the arraylist contents without a DataSource, adding and removing items via
comparison as you suggest.
 
M

MCDave

I wrote some working code for what I needed - no 3rd party control
necessary.
For everyone's scrutiny:
Basically, there are 2 listboxes bound with arraylists, both needed to be
populated from the DB showing the regions that currently belong to the
salesrep on the left side and regions that do not belong to the salesrep on
the right side (wasn't thinking clearly earlier - damn, it's hard to
concentrate while on pain medication!).

///
Private alRegionNames As New ArrayList 'left hand listbox
Private alSelectedRegionNames As New ArrayList

Private Sub form4_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
loadDBRegionNames()
End Sub

Private Sub loadDBRegionNames()
alRegionNames = SalesRegionsDB.GetAvailRegNamesForSA(1) 'gets all
regions that are not already assigned to a salesman
Me.SetRightListboxDataSource(alRegionNames)

alSelectedRegionNames = SalesRegionsDB.GetRegionNamesForSA(1) 'gets
currently assigned regions
Me.SetLeftListboxDataSource(alSelectedRegionNames)
End Sub

Private Sub SetLeftListboxDataSource(ByRef dsL As ArrayList)
lstSelectedRegionNames.DisplayMember = "reg_name"
lstSelectedRegionNames.ValueMember = "reg_idx"
lstSelectedRegionNames.DataSource = dsL
End Sub

Private Sub SetRightListboxDataSource(ByRef dsR As ArrayList)
lstRegionNames.DisplayMember = "reg_name"
lstRegionNames.ValueMember = "reg_idx"
lstRegionNames.DataSource = dsR
End Sub

Private Sub Add()
Dim sindex As Integer = Me.lstRegionNames.SelectedIndex
If sindex < 0 Then Return

Dim sr As New SalesRegionDD
sr = Me.lstRegionNames.SelectedItem

Dim itemcount As Integer = Me.lstRegionNames.Items.Count

Me.alSelectedRegionNames.Add(sr)
Me.alRegionNames.RemoveAt(sindex)

Me.SetLeftListboxDataSource(Me.alSelectedRegionNames.Clone)
'I put this test in to see if there is only 1 item left in the
listbox, if so,
' it sets the datasource to nothing (or else there will be a very
noticeable delay for the last item to pass over to the other box)
If itemcount = 1 Then
Me.lstRegionNames.DataSource = Nothing
Else
Me.SetRightListboxDataSource(Me.alRegionNames.Clone) 'if you
use the clone, then you don't have to set the datasource to nothing first -
go figure!
End If

End Sub

Private Sub AddAll()
Me.alSelectedRegionNames.AddRange(Me.alRegionNames)
Me.alRegionNames.Clear()
Me.lstRegionNames.DataSource = Nothing
Me.SetLeftListboxDataSource(Me.alSelectedRegionNames.Clone)
End Sub

Private Sub RemoveAll()
Me.alRegionNames.AddRange(Me.alSelectedRegionNames)
Me.alSelectedRegionNames.Clear()
Me.lstSelectedRegionNames.DataSource = Nothing
Me.SetRightListboxDataSource(Me.alRegionNames.Clone)
End Sub

Private Sub Remove()
Dim sindex As Integer = Me.lstSelectedRegionNames.SelectedIndex
If sindex < 0 Then Return

Dim sr As New SalesRegionDD
sr = Me.lstSelectedRegionNames.SelectedItem

Dim itemcount As Integer = Me.lstSelectedRegionNames.Items.Count
Me.alRegionNames.Add(sr)
Me.alSelectedRegionNames.RemoveAt(sindex)

If Me.lstSelectedRegionNames.Items.Count > 0 Then
Me.lstSelectedRegionNames.SelectedIndex = 0
End If

Me.SetRightListboxDataSource(Me.alRegionNames.Clone)

If itemcount = 1 Then
Me.lstSelectedRegionNames.DataSource = Nothing
Else
Me.SetLeftListboxDataSource(Me.alSelectedRegionNames.Clone)
End If
End Sub

Private Sub btnAdd_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnAdd.Click
Me.Add()
End Sub

Private Sub btnRemove_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnRemove.Click
Me.Remove()
End Sub

Private Sub btnAddAll_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnAddAll.Click
AddAll()
End Sub

Private Sub btnRemoveAll_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles btnRemoveAll.Click
RemoveAll()
End Sub
\\\

Many thanks to all who helped in this endeavor,

MCDave
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top