The Access Management form
This is the form that will manage the junction table UserSystem. Since we don’t want a form where we need to enter the UID and the SID for each relation we want, we need to create a more complex interface.
Design
First of all, add a new form to your project:
- Click Project → Add Windows form…
- Rename it to formAccess;
- Create your form as follows (pick each control from toolbox – the properties will be explained later):

Toolbox
|
|
Control name
|
Control type
|
Properties
|
|---|---|---|---|
|
(1)
|
ds
|
DataSet
|
DataSetName=AccessControlDataSet
|
|
(1)
|
tam
|
TableAdapterManager
|
|
|
(1)
|
bs_u
|
BindingSource
|
DataSource=ds
DataMember=Users |
|
(1)
|
ta_s
|
SystemsTableAdapter
|
|
|
(1)
|
ta_us
|
UserSystemTableAdapter
|
|
|
(1)
|
ta_u
|
UsersTableAdapter
|
|
|
(2)
|
cmbUsers
|
ComboBox
|
DropDownStyle=DropDownList
DataSource=bs_u
DisplayMember=Name ValueMember=UID |
|
(3)
|
lbUnenrolled
|
ListBox
|
SelectionMode=MultiSimple
DisplayMember=System
|
|
(4)
|
lbEnrolled
|
ListBox
|
SelectionMode=MultiSimple
DisplayMember=System
|
|
(5)
|
cmdEnroll
|
Button
|
|
|
(5)
|
cmdUnenroll
|
Button
|
|
|
(6)
|
cmdOK
|
Button
|
|
|
(6)
|
cmdCancel
|
Button
|
|
Coding
First of all, we need to define the form behavior and actions. Here they are:
- When loaded, the form must read the database into our datasets;
- The cmbUsers must show the user names (Name property at Users dataset);
- The lbEnrolled displays a selectable list of systems (System property at Systems dataset) the selected user is enrolled to;
- The lbUnrenrolled displays a selectable list of systems (from System column at Systems dataset) the selected user is NOT enrolled to;
- When the user shown on cmbUsers is changed, the content of lbEnrolled and lbUnenrolled must be updated to match the users info;
- When clicked, cmdEnroll enrolls the user to systems selected on lbUnrenrolled, creating a new row on UserSystem dataset;
- When clicked, cmdUnenroll dismiss the user from systems selected on lbEnrolled, removing the corresponding row from UserSystem dataset;
- When cmdOK is clicked, the changes on UserSystem dataset are updated to database and the form is closed;
- When cmdCancel is clicked, the changes on table UserSystem dataset are rejected and the form is closed;
Load
When the form is loaded, we must load the database into our datasets (i). To do so, we use the Fill function on each table adapter:
ta_us.Fill(ds.UserSystem) ‘ Populate UserSystem DataSet
ta_s.Fill(ds.Systems) ‘ Populate Systems DataSet
ta_u.Fill(ds.Users) ‘ Populate Users DataSet
Behavior
We form behavior is set on form design by setting the desired properties on each form control. For instance, we want the user names displayed on cmbUsers (ii). It can be done using the following cmbUsers properties:
- DropDownStyle=DropDownList: set control as a drop-down read-only list;
- DataSource=bs_u: set “bs_u” as the list containing the items to display;
- DisplayMember=Name: set “Name” as the bs_u property containing the displaying value;
- ValueMember=UID: set “UID” as the bs_u property containing the actual value;
To ensure that it works fine, we also need to set the bs_u properties:
- DataSource=ds: set “ds” as the data source that the connector binds to;
- DataMember=Users: set “Users” as the ds property containing the list to which the connector currently binds to;
Basically, these properties binds bs_u to Users dataset and cmbUsers uses it as a list containing the elements to be displayed. The main advantages of using a binding source instead of using a local list populated with user names is that we use much less code (no need of using a function to populate the list) and all cmbUsers events are magically bound to Users dataset events. In fact, we set its DropDownStyle property as read-only to avoid any edition in this field, which would also change the bound contents on Users dataset.
Populate
We need to populate lbEnrolled (iii) and lbUnenrolled (iv) with Systems dataset contents. To make it easier, we add the whole row to each control and set their DisplayMember property (during form design) to “System”, ensuring that the row’s System property is shown on control interface. We also want multiple item selection on these boxes. To do so, we set their SelectionMode property to MultiSimple.
The code that populates these boxes is shown below. It gets the UID from the row bound to the current cmbUsers item (the Current property) and processes each row on Systems dataset, adding it to lbEnrolled or lbUnenrolled depending on the existence of an entry on UserSystem dataset:
Dim u As AccessControlDataSet.UsersRow
Dim s As AccessControlDataSet.SystemsRow
lbEnrolled.Items.Clear() ‘ Clear all items on lbEnrolled
lbUnenrolled.Items.Clear() ‘ Clear all items on lbUnenrolled
u = CType(bs_u.Current, DataRowView).Row ‘ Get current Users row
For Each s In ds.Systems.Rows ‘ For each row on Systems:
Dim us As Boolean
Dim qr As String
qr = “SID = “ & s.SID & “ and UID = “ & u.UID ‘ - QUERY: matching SID/UID
us = ds.UserSystem.Select(qr).Length > 0 ‘ - Query UserSystem, true if exists
If us Then ‘ - True?
lbEnrolled.Items.Add(s) ‘ -- add row to lbEnrolled
Else ‘ - False?
lbUnenrolled.Items.Add(s) ‘ -- add row to lbUnenrolled
End If
Next ‘ Go to next Systems row
Since there are several form actions that repopulate these controls, we’re creating a subroutine containing this code, called PopulateListBoxes().
Events
There are some events that must be handled by this form. The first one is processing the user changed; we need to repopulate lbUnenrolled and lbEnrolled (v) when it happens. Well, when the item bound to the cmbUsers is changed, the related binding source (bs_u) generates an event called PositionChanged, indicated that the value of its Position property changed. So, it’s enough to call the PopulateListBoxes() subroutine when it happens:
If bs_u.Position >= 0 Then ‘ Is position valid?
PopulateListBoxes() ‘ - repopulate list boxes
End If
The if clause is required because this event is also triggered when Users dataset is populated (form loading above) twice, once during dataset cleaned-up (required before loading database contents) and a second time when the data is finally loaded. Well, during cleaning-up, bs_u.Position is -1 (indicating that dataset is empty) and bs_u.Current is void, causing an error when we read this property to get UID value.
The next event is when cmdEnroll is clicked: the selected used must be enrolled to each selected systems on lbUnenrolled list (vi). Each enrollment is done by creating a new row, populating it with current UID/SID values and adding it to the UserSystem dataset:
Dim u As AccessControlDataSet.UsersRow
Dim s As AccessControlDataSet.SystemsRow
u = CType(bs_u.Current, DataRowView).Row ‘ Get current Users row
For Each s In lbUnenrolled.SelectedItems ‘ For each selected item on lbUnenrolled:
Dim us As AccessControlDataSet.UserSystemRow
us = ds.UserSystem.NewUserSystemRow() ‘ Create new UserSystem row
us.UID = u.UID ‘ Set row’s UID property
us.SID = s.SID ‘ Set row’s SID property
ds.UserSystem.AddUserSystemRow(us) ‘ Add new row to UserSystem
Next
PopulateListBoxes() ‘ Repopulate list boxes
The opposite event occurs when cmdUnenroll is clicked (vii): the selected user must be dismissed from selected systems on lbEnrolled list. Each dismiss is done by searching the corresponding row and removing it from UserSystem dataset:
Dim u As AccessControlDataSet.UsersRow
Dim s As AccessControlDataSet.SystemsRow
u = CType(bs_u.Current, DataRowView).Row ‘ Get current Users row
For Each s In lbEnrolled.SelectedItems ‘ For each selected item on lbEnrolled:
Dim us As AccessControlDataSet.UserSystemRow
Dim qr As String
qr = “SID = “ & s.SID & “ and UID = “ & u.UID ‘ - QUERY: matching SID/UID
us = ds.UserSystem.Select(qr)(0) ‘ - Query UserSystem, return matching row
ds.UserSystem.RemoveUserSystemRow(us) ‘ - Remove it from UserSystem
Next
PopulateListBoxes() ‘ Repopulate list boxes
The last two events are triggered when cmdOK (viii) or cmdCancel (ix) is clicked. In the first case, we need to update the changes on dataset to database and then close the form:
Validate() ‘ Validate form
bs_u.EndEdit() ‘ Apply pending changes
tam.UpdateAll(ds) ‘ Update all datasets
Close() ‘ Close form
The Validate() call just generate form validation events, verifying the values on all form controls, bs_u.EndEdit() just applies the pending changes to data source bound to it and tam.UpdateAll(ds) updates all datasets in the form. These calls are default when dealing with datasets and binding sources.
On the other hand, when cmdCancel is clicked, it’s enough to close the form without updating anything. For code clarity, we also reject all dataset changes (this call can be safely removed):
ds.RejectChanges() ‘ Reject all changes to datasets
Close() ‘ Close form
The management form
This is our simplest form and will be used to handle all the others.
Design
First of all, add a new form to your project:
- Click Project → Add Windows form…
- Rename it to formManagement;
- Create your form as follows:

Coding
Just add handlers to each button to open the referred form (formFingerprints is defined ahead):
- Users button is clicked: open formUsers form using ShowDialog() function:
formUsers.ShowDialog()
- Systems button is clicked: same for formSystems
- Fingerprints button is clicked: same for formFingerprints
- Access button is clicked: same for formAccess
- Exit button is clicked: close the form:
formUsers.ShowDialog()
The ShowDialog function opens the referred form and waits until the form is closed.