Learn Microsoft Access Advanced Programming Techniques, Tips and Tricks.

Showing posts with label ListView Control. Show all posts
Showing posts with label ListView Control. Show all posts

ListView Control Drag-Drop Sort Events

Rearranging Rows of Data with the ListView Control.

In an earlier part of this tutorial, we explored how to rearrange columns in the ListView by enabling the AllowColumnReorder option on the Property Sheet.

However, rearranging rows (list items) works differently. Rows can be relocated by dragging and dropping them onto another row. To enable this functionality, we must first activate the OLEDragMode / OLEDropMode options of the ListView control on the Property Sheet.

But enabling these options alone is not enough—VBA code is required to complete the drag-and-drop operation and actually rearrange the items into the desired order.

To demonstrate this, let us build a sample Access Form with the required controls and VBA code. The form will include:

  • A ListBox to display item indexes,

  • A ListView control with sample data,

  • VBA code to handle the drag-and-drop sequence and rearrange the rows accordingly.

A sample image of the form, featuring ListBox and ListView controls, is shown below.


We have created a ListBox that displays all the Tables and Queries (excluding Action Queries) from the database.

When you select an item from the listbox, the corresponding records are instantly displayed on the ListView control, in the same way they appear in Datasheet View.

The Design Task.

Step-by-Step Setup

  1. Create the Source Table

    • Create a new table with a single Text field, and name it DataList.

    • Save the table as lvTables (here, lv stands for ListView).

    • Open the table in Datasheet View and add a few table names and Select Query names from your database.

    • (Example: I used tables imported from the Northwind sample database.)

    Note: The Attachment field type is not supported in the ListView control. For tables containing attachments, create a Select Query that includes all fields except the attachment field.


  1. Create the Form Layout

    • Open a new form in Design View.

    • Insert a ListBox control.

      • Set its Name property to List0.

      • Change the label’s caption to 'Tables'.

      • In the Property Sheet, set:

        • Row SourcelvTables

        • Row Source TypeTable/Query

        • Bound Column1

    • Insert a ListView control from the ActiveX Controls list.

      • Change its Name property to ListView1.

      • Resize both the ListBox and ListView controls as shown in the demo form image above.

    • Insert a Label above the controls.

      • Set its Name to Heading.

      • Set its Caption to Heading (this will later be updated by VBA code).

    • Insert a Command Button below the controls.

      • Set its Name to cmdClose.

      • Set its Caption to Close.


  1. Configure the ListView Control

    • Right-click on the ListView control → highlight ListViewCtrl Object → select Properties.

    • On the General Tab, adjust the settings to match the sample image provided below.

    Some of these options we have already set in the earlier sessions. Here we need the following options for our Drag and Drop action:

    • OLEDragAutomatic - 1

    • OLEDropManual - 1

    • FullRowSelect - True

    • HotTracking - True

Ensure that the above settings match your property sheet, then save the Form.

Display the VBA Module of the Form.

The Form Module VBA Code.

Copy and paste the following VBA Code into the Form Module, overwriting the existing Code Lines, if any:

Option Compare Database
Option Explicit

Dim lvwList As MSComctlLib.ListView
Dim strTable As String
Dim db As DAO.Database
Dim rst As DAO.Recordset

Private Sub Form_Load()
    Set lvwList = Me.ListView1.Object

End Sub


Private Sub Form_Unload(Cancel As Integer)
On Error GoTo Form_Unload_Err
Dim lvItem As ListItem
Dim tmp As Long
Dim criteria As String
Dim strfield As String
Dim flag As Boolean
Dim fld As String

If strTable = "" Then
Set lvwList = Nothing
    Exit Sub
End If

Set db = CurrentDb
Set rst = db.OpenRecordset(strTable, dbOpenDynaset)
flag = False
For Each lvItem In lvwList.ListItems
    tmp = lvItem.Index
    strfield = lvwList.ColumnHeaders(1).Text
    criteria = strfield & " = " & Chr(34) & lvItem.Text & Chr(34)
    
    rst.FindFirst criteria
  
    If Not rst.NoMatch Then
       If (rst.Fields(strfield).Value = lvItem.Text) _
       And (rst.Fields(1).Value = tmp) Then
         'GoTo nextitem
       Else
            rst.Edit
            rst.Fields(1).Value = tmp
            rst.Update
       End If
    Else
        MsgBox "Item: " & tmp & " Not Found!"
    End If
Next
rst.Close

Set lvwList = Nothing
Set lvItem = Nothing
Set rst = Nothing
Set db = Nothing

Form_Unload_Exit:
Exit Sub

Form_Unload_Err:
MsgBox Err & " : " & Err.Description, , "Form_Unload()"
Resume Form_Unload_Exit

End Sub

Private Sub ListView1_ColumnClick(ByVal ColumnHeader As Object)
' When a ColumnHeader object is clicked, the ListView control
' sorts the data of that column. On the first Click on the Column
'will sort in Ascending Order, second Click will sort in Descending
With Me.ListView1
    ' Set the SortKey to the Index of the ColumnHeader - 1
    .SortKey = ColumnHeader.Index - 1
    
' Set Sorted to True to sort the list.
 If .SortOrder = lvwAscending Then
    .SortOrder = lvwDescending
 Else
    .SortOrder = lvwAscending
 End If
 
    .Sorted = True
End With

End Sub

Private Sub List0_Click()

strTable = List0.Value

Call LoadListView(strTable)

End Sub

Private Sub LoadListView(ByVal s_Datasource As String)
On Error GoTo LoadListView_Err
    Dim j As Integer
    Dim tmpLItem As MSComctlLib.ListItem
    Dim strHeading As String
    
    strHeading = UCase(s_Datasource)
    With Me.Heading
        .caption = strHeading
        .FontName = "Courier New"
        .FontSize = 20
        .FontItalic = True
        .FontBold = True
    End With
    
   'Initialize ListView Control
    lvwList.ColumnHeaders.Clear
    lvwList.ListItems.Clear
    
    Set db = CurrentDb
    Set rst = db.OpenRecordset(s_Datasource, dbOpenSnapshot)
       
    'Initialize ListView & Column Headers Property Values
     With lvwList
        .Font.Size = 10
        .Font.Name = "Verdana"
        .Font.Bold = False
        .GridLines = True
    End With
    
    With lvwList
        'Syntax: .ColumnHeaders.Add Index, Key, Text, Width in Pixels, Alignment, Icon
       For j = 0 To rst.Fields.Count - 1
        .ColumnHeaders.Add , , rst.Fields(j).Name, IIf(j = 0, 3000, 1400), 0
       Next
    End With
   Dim I As Long
    rst.MoveFirst
    Do While Not rst.BOF And Not rst.EOF
    'Syntax: lvwList.ListItems.Add Index, Key, Text, Icon, SmallIcon
        Set tmpLItem = lvwList.ListItems.Add(, , rst.Fields(0).Value) 'Name column
        
         'Syntax: tmpLItem.ListSubItems.Add Index, Key, Text, ReportIcon, ToolTipText
          With tmpLItem
                For j = 1 To rst.Fields.Count - 1
                    .ListSubItems.Add , , Nz(rst.Fields(j).Value, "")
                Next
          End With
        rst.MoveNext
    Loop
    rst.Close
    
    With lvwList
        If .ListItems.Count > 0 Then
            .ListItems(1).Selected = True
        End If
    End With
  
    Set db = Nothing
    Set rst = Nothing
    
LoadListView_Exit:
Exit Sub

LoadListView_Err:
MsgBox Err & " : " & Err.Description, , "LoadListView()"
Resume LoadListView_Exit
End Sub


Private Sub ListView1_OLEDragOver(data As Object, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single, State As Integer)
    'Highlight the item when draged over it
    Set ListView1.DropHighlight = ListView1.HitTest(x, y)

End Sub

Private Sub ListView1_OLEDragDrop(data As Object, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single)

'Item being dropped
Dim lvwDrag As ListItem
'Item being dropped on
Dim lvwDrop As ListItem
'Item being readded to the list
Dim lvwTarget As ListItem
'Subitem reference in dropped item
Dim lvwSub As ListSubItem
'Drop position
Dim intTgtIndex As Integer
Dim j As Integer

Set lvwDrop = lvwList.HitTest(x, y)
Set lvwDrag = lvwList.SelectedItem 'save a copy of draged item

'Ignore overlapping drag or drop Item actions
If (lvwDrop Is Nothing) Or (lvwDrag Is Nothing) Or (lvwDrop = lvwDrag) Then
    Set lvwList.DropHighlight = Nothing
    Set lvwDrop = Nothing
    Set lvwDrag = Nothing
    Exit Sub
End If

'Save the droped position Index Number
intTgtIndex = lvwDrop.Index
'Remove Dragged Item from its old position
lvwList.ListItems.Remove lvwDrag.Index

'For j = intTgtIndex To ListItems.Count
    
'Creates a new Item in the Target Item position
'with the Dropped Item Index Number and Dragged Item.Text.
'Saves the new Item reference in lvwTarget Item.

'* The original Droped-on Target) Item will be moved down
'* by incrementing its original Index Number
Set lvwTarget = lvwList.ListItems.Add(intTgtIndex, , lvwDrag.Text)

'Copy the original Draged Item's subitems to the new item
If lvwDrag.ListSubItems.Count > 0 Then
    For Each lvwSub In lvwDrag.ListSubItems
        lvwTarget.ListSubItems.Add , lvwSub.Key, lvwSub.Text
    Next
End If

'Highlight the draged item in its new position
lvwTarget.Selected = True

'Destroy all objects
Set lvwTarget = Nothing
Set lvwDrag = Nothing
Set lvwDrop = Nothing
Set lvwList.DropHighlight = Nothing

End Sub

Private Sub cmdClose_Click()
    DoCmd.Close acForm, Me.Name
End Sub

You are already familiar with most of the VBA code, except for the newly added procedures:

  • ListView1_OLEDragOver()

  • ListView1_OLEDragDrop()

  • Form_Unload()

  • ListView1_ColumnClick()

The first two procedures handle the drag-and-drop functionality, allowing a ListItem (row) to be dragged and placed in a new location. The Form_Unload() and ListView1_ColumnClick() procedures are used to sort the ListItems.

The images below illustrate the drag-and-drop process:

  1. In the first image, the ListItem with EmployeeID = 7 is dragged upward by the user and dropped onto the ListItem with EmployeeID = 3.

  2. In the second image, the ListItem is moved in the reverse order.

  3. As the mouse pointer moves over the rows during the drag operation, each row between the source and target items is highlighted in sequence, providing a clear visual cue of the drop location.

The Drag and Drop Action in Pictures.

The row with Employee ID 7 is dropped on the Item, with Employee ID 3 above.

The VBA Code Segment-wise Analysis.

In an item selected from the ListBox, the List0_Click() event procedure runs and loads the records in the ListView Control.

Private Sub List0_Click()
Dim strTable As String

strTable = List0.Value

  Call LoadListView(strTable)

End Sub

The selected Table or Query name is stored in the strTable string variable. This variable is then passed as a parameter to the LoadListView() subroutine. We have already reviewed this procedure in earlier sessions. If you would like to revisit those explanations, please refer to the links provided at the bottom of this page. You may also notice a few minor adjustments that I have made to the code in this episode.

In this example, we have not used the ImageList Control. Consequently, the Icon, SmallIcon parameter values in the ListItems.Add() method, as well as the ReportIcon and TooltipText parameters are also not applied.

Now, let us turn our attention to the drag-and-drop functionality. Specifically, we will examine how the VBA code within the ListView1_OLEDragOver() and ListView1_OLEDragDrop() procedures work.

The ListView1_OLEDragOver() Procedure.

Private Sub ListView1_OLEDragOver(Data As Object, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single, State As Integer)
    'Highlight the item when draged over it
    Set ListView1.DropHighlight = ListView1.HitTest(x, y)
End Sub 

This procedure is executed automatically when you click and hold on a row, then start dragging it across the ListView control. As the dragged row passes over other rows on the way to the target position, each row beneath the pointer is highlighted in turn.

The function ListView1.HitTest(x, y) is used to read the current mouse pointer coordinates (x, y). Based on these coordinates, it determines which row of the ListView control is currently under the pointer and highlights that row.

This process continues as you move over additional rows until you finally release the mouse button on the chosen target row. At this point, the drop action triggers the ListView1_OLEDragDrop() procedure, which executes the code necessary to reposition the source row into its new location.

The ListView1_OLEDragDrop Procedure.

Private Sub ListView1_OLEDragDrop(Data As Object, Effect As Long, Button As Integer, Shift As Integer, x As Single, y As Single)

'Item being dragged
Dim lvwDrag As ListItem
'Item being dropped on
Dim lvwDrop As ListItem
'Item being added to the list
Dim lvwTarget As ListItem
'Subitem reference used in For . . .Next loop
Dim lvwSub As ListSubItem 'Drop position index Dim intTgtIndex As Integer Set lvwDrop = lvwList.HitTest(x, y) 'save the source item Set lvwDrag = lvwList.SelectedItem 'save a copy of draged item 'Ignore overlapping drag or drop Item actions If (lvwDrop Is Nothing) Or (lvwDrag Is Nothing) Or (lvwDrop = lvwDrag) Then Set lvwList.DropHighlight = Nothing Set lvwDrop = Nothing Set lvwDrag = Nothing Exit Sub End If 'Save the droped position Index Number intTgtIndex = lvwDrop.Index 'Remove Dragged Item from its old position lvwList.ListItems.Remove lvwDrag.Index 'Creates a new Item in the Target Item position 'with the Dropped Item Index Number and Dragged Item.Text. 'Saves the new Item reference in lvwTarget Item. '* The original Droped-on Target) Item will be moved down '* by incrementing its original Index Number Set lvwTarget = lvwList.ListItems.Add(intTgtIndex, , lvwDrag.Text) 'Copy the original Draged Item's subitems to the new item If lvwDrag.ListSubItems.Count > 0 Then For Each lvwSub In lvwDrag.ListSubItems lvwTarget.ListSubItems.Add , lvwSub.Key, lvwSub.Text Next End If 'Highlight the draged item in its new position lvwTarget.Selected = True 'Destroy all objects Set lvwTarget = Nothing Set lvwDrag = Nothing Set lvwDrop = Nothing Set lvwList.DropHighlight = Nothing End Sub

Let us now review this procedure in detail, breaking it down into smaller sections to understand its functionality.

The first part of the code declares the necessary object variables that will be used to handle the drag-and-drop action within the ListView control:

'Item being dragged
Dim lvwDrag As ListItem
'Item being dropped on
Dim lvwDrop As ListItem
'Reference of the Item being added to the list
Dim lvwTarget As ListItem
'Subitem reference used in For . . .Next loop
Dim lvwSub As ListSubItem
'Drop position index
Dim intTgtIndex As Integer

Set lvwDrop = lvwList.HitTest(x, y)
Set lvwDrag = lvwList.SelectedItem 'save a copy of draged item

In this procedure, the first three temporary ListItem objects are declared, each serving a distinct role in the drag-and-drop process:

  • lvwDrag – Holds a copy of the row being dragged to a new location.

  • lvwDrop – Stores a reference to the row on which the dragged item will be dropped.

  • lvwTarget – Points to the newly created ListItem after the source row is removed from its original location and re-inserted at the target position.

Additionally, the lvwSub variable is declared as a sequencing object. It is used in the For...Next loop to cycle through all ListSubItems (columns from the 2nd onward) of the dragged row. Even though the original ListItem is deleted during the process, a complete copy of it is preserved in lvwDrag, allowing its sub-items to be transferred one by one.

The target index is stored in the intTgtIndex variable, which captures the position of the ListItem where the dragged row will be re-inserted.

To determine this position, the function lvwList.HitTest(x, y) reads the current mouse coordinates over the ListView control. It identifies the target ListItem and assigns it to the lvwDrop object.

Since a row must be selected before it can be dragged, the lvwList.SelectedItem property value is set to True. Using this property, a copy of the selected ListItem is made into the lvwDrag object.

The next code segment then validates both the source (lvwDrag) and target (lvwDrop) objects before proceeding with the row rearrangement.

Validation Checks on the Drag-Drop Action.

'Ignore overlapping drag or drop Item actions, 
'OR drag and drop happens on the same ListItem.
If (lvwDrop Is Nothing) Or (lvwDrag Is Nothing)  Or (lvwDrop = lvwDrag) Then
    Set lvwList.DropHighlight = Nothing
    Set lvwDrop = Nothing
    Set lvwDrag = Nothing
    Exit Sub
End If

This code segment is responsible for validating the drag-and-drop action before any changes are made.

If the drag operation does not begin or end on a valid item, either the lvwDrag or lvwDrop object (or both) will be empty. Another invalid scenario occurs when the user starts to drag a row but then drops it back onto the same row—effectively making no change.

In such cases, the procedure detects the invalid move and terminates execution immediately, preventing errors or unnecessary processing.

If the validation passes, the program proceeds to the next section of code, where the rows in the ListView are rearranged according to the drag-and-drop action.

'Save the dropped position ListItem Index Number
intTgtIndex = lvwDrop.Index

'Remove Dragged Item from its old position
lvwList.ListItems.Remove lvwDrag.Index

'Creates a new Item in the Target Item position
'with the Dropped Item Index Number and Dragged Item.Text.
'Saves the new Item reference in lvwTarget Item.

'* The original Droped-on Target) Item will be moved down
'* by incrementing its original Index Number
Set lvwTarget = lvwList.ListItems.Add(intTgtIndex, , lvwDrag.Text)

'Copy the original Draged Item's subitems to the new item
If lvwDrag.ListSubItems.Count > 0 Then
    For Each lvwSub In lvwDrag.ListSubItems
        lvwTarget.ListSubItems.Add , lvwSub.Key, lvwSub.Text
    Next
End If

'Highlight the draged item in its new position
lvwTarget.Selected = True

The above nine executable lines of code (excluding comments) carry out the drag-and-drop operation in a fairly straightforward manner.

  1. Target Index Capture

    intTgtIndex = lvwDrop.Index

    The target row’s index number is saved in the variable intTgtIndex.

  2. Removing the Source Item
    Since the source row (ListItem) is already stored in the temporary lvwDrag object, the next step is to remove it from its original position:

    lvwList.ListItems.Remove lvwDrag.Index

    This ensures the item no longer exists in its original location before being recreated at the new position.

  3. Re-creating the Item at the Target Location
    The dropped item is reinserted at the target index with its text value preserved from lvwDrag:

    Set lvwTarget = lvwList.ListItems.Add(intTgtIndex, , lvwDrag.Text)

    (Note: Only the Index and Text parameters are used here. Other options like Key, Icon, and SmallIcon are not included, but if they had been used originally, they would also need to be copied from the lvwDrag object.)

  4. Automatic Index Adjustment
    When inserting the dragged item into its new position, the ListView control automatically shifts existing items.

    • Example: If the 7th item is dragged and dropped onto the 3rd, the new item is created at index 3.

    • The original item at index 3, and all subsequent items, are automatically pushed forward one position (3→4, 4→5, etc.) to make space for the incoming item.


✅ In short, the drag-and-drop action is achieved by removing the source ListItem and then re-creating it at the target index, while the control automatically manages the resequencing of the remaining items.

The Impact of Deleting a Row and Creating it Elsewhere. 

Dragging a Row Downwards (Example: Item 3 → Item 7)

When you drag ListItem 3 and drop it on ListItem 7, two automatic index shifts happen:

  1. Deletion Phase

    • When Item 3 is deleted, all subsequent items shift up one position.

    • So, items 4,5,6,7,8,9 → become 3,4,5,6,7,8.

    • The original item 7 is now sitting at position 6.

  2. Insertion Phase

    • When the dragged item is recreated at index 7, the ListView again adjusts indexes.

    • The current items 7,8 → shift down to 8,9 to make room.

    • Thus, the dragged item now occupies index 7 at the new location.

📌 Visual Effect: It looks like the dragged row (3) has “jumped down” the list, while the original target row (7) has moved up temporarily during deletion, then shifted back down when the new item was inserted.


Dragging a Row Upwards (Example: Item 7 → Item 3)

  • In the reverse scenario (dragging 7 to 3), deletion of item 7 makes items 8,9… shift up.

  • When the dragged item is inserted at index 3, the existing items 3,4,5… are shifted down to accommodate it.

  • 📌 Visual Effect: The target row at index 3 appears to “move down” while the dragged row slides into its place.


Key Insight

The ListView control itself manages this re-sequencing. Your VBA code only needs to:

  • Remove the dragged item from its original index.

  • Recreate it at the target index.

The rest — shifting items up or down — happens automatically.


Important Note

  • The term ListItem always refers to the first column (the row header, e.g., Employee ID).

  • The other column values are ListSubItems (children of the ListItem).

  • During drag-and-drop, you’re really moving only the first column (the parent).

  • The associated ListSubItems must be re-attached programmatically in the loop (lvwSub) so the entire row moves as one unit.

This is true if you have not enabled the FullRowSelection on the ListView Control Property Sheet on the General Tab.

If column selection is enabled, you can click on any column to start a drag-and-drop action. However, the system always relies on the ListItem Index (the first column) to determine the row reordering sequence. Compare the earlier two images with the third and fourth sample images shown above on this page for a clearer understanding.

For drag-and-drop to work, you must configure the following properties on the ListView Control (Property Sheet → General Tab):

ccOLEDragAutomatic = 1 ccOLEDropManual = 1

Once these settings are applied:

  1. The next five statements in the code transfer all ListSubItems (if any) to the newly created ListItem in the target location.

  2. The newly created ListItem is then highlighted to confirm the move.

  3. Finally, all temporary object variables are cleared from memory.

⚠️ Important: This arrangement is only temporary. Any changes are lost when you close the form or reload a new table/query into the ListView control.

If you want the rearranged order to persist (i.e., remain even after reopening), you must update the table with the new order. To support this, we added a new Integer field named ID to the Employees table, which stores the row order explicitly.

Below is a sample screen showing the Employee records rearranged in alphabetical order, with their updated indexed order stored in the ID field.

Since the EmployeeID field is an AutoNumber and is linked with several related tables, it cannot be modified or repurposed for row reordering. To handle this, we added a new Number field named ID to the Employees table.

  • The ID field is initialized with values matching the current sequence of EmployeeID numbers.

  • Initially, the ID field values follow the same order as the EmployeeID.

  • However, when you rearrange rows in the ListView Control using the drag-and-drop feature, the visual order of rows changes—even though the underlying EmployeeID remains untouched.

Since the EmployeeID field is an AutoNumber and is linked with several related tables, it cannot be modified or repurposed for row reordering. To handle this, we added a new Number field  ID to the Employees table.

  • The ID Field is initialized with values matching the current sequence of EmployeeID numbers.

  • Initially, the ID field values follow the same order as the EmployeeID.

  • However, when you rearrange rows in the ListView Control using the drag-and-drop feature, the visual order of rows changes—even though the underlying EmployeeID remains untouched.

The purpose of this ID field is to store and persist the display order of the records. By updating this field during drag-and-drop operations, we can ensure that the reordered sequence remains intact the next time the form is opened or the data is reloaded.

Look at the EmployeesQ Query SQL given below:

SELECT [FirstName] & " " & [LastName] AS EmployeeName, 
Employees.ID, 
Employees.EmployeeID, 
Employees.TitleOfCourtesy, 
Employees.Title, 
Employees.Address, 
Employees.City, 
Employees.Region, 
Employees.PostalCode, 
Employees.Country, 
Employees.HomePhone, 
Employees.Extension, 
Employees.Notes
FROM Employees
ORDER BY Employees.ID;

The Employees query, used as the data source for the ListView Control, is sorted by the custom ID field. Whenever the rows are rearranged in the ListView through drag-and-drop, the corresponding ID values are updated to reflect the new order.

This updating process is executed in the Form_Unload() event procedure, which runs when the form is closed. By writing the modified index values back to the table at this point, we ensure that the new sequence is preserved.

As a result, the next time the form is opened, the ListView Control will display the records in the same order they were last arranged, rather than resetting to the default EmployeeID sequence.

The Form_Unload() Event Procedure VBA Code.

Private Sub Form_Unload(Cancel As Integer)
Dim lvItem As ListItem
Dim tmp As Long
Dim criteria As String
Dim strfield As String
Dim fld As String

If strTable = "" Then
Set lvwList = Nothing
    Exit Sub
End If

Set db = CurrentDb
Set rst = db.OpenRecordset(strTable, dbOpenDynaset)

For Each lvItem In lvwList.ListItems
    tmp = lvItem.Index
    strfield = lvwList.ColumnHeaders(1).Text 'EmployeeName
    criteria = strfield & " = " & Chr(34) & lvItem.Text & Chr(34)
    
    rst.FindFirst criteria
  
    If Not rst.NoMatch Then
       If (rst.Fields(strfield).Value = lvItem.Text) And (rst.Fields(1).Value = tmp) Then
         'GoTo nextitem
       Else
            rst.Edit
            rst.Fields(1).Value = tmp 'replace ID number
            rst.Update
       End If
    Else
        MsgBox "Item: " & tmp & " Not Found!"
    End If
Next
rst.Close

Set lvwList = Nothing
Set lvItem = Nothing
Set rst = Nothing
Set db = Nothing

End Sub

How the Reordered Data is Saved Permanently

In the screenshot, notice that the EmployeeName values are arranged in alphabetical order on the ListView Control. The ID field in the Employees table, however, does not initially follow this sequence.

The goal is to update the ID field so that it reflects the current row order of the ListView Control. Here’s how the procedure works step by step:

  1. ListItem Text Value

    • The first column of the ListView row (ListItem.Text) contains the employee’s name.

    • Since the ListItems are arranged alphabetically, their index numbers run from 1 to 9 (in the displayed order).

  2. Finding the Corresponding Record

    • For each ListItem, the employee’s name is extracted.

    • A search (rst.FindFirst) is performed in the Employees table/query to locate the matching record.

  3. Updating the ID Field

    • When the matching record is found, the ListItem’s current index number is written back into the table’s ID field.

    • This operation is repeated for all ListItems in the control.

  4. Handling an Empty ListView

    • At the start of the Form_Unload procedure, we first check whether any source data has been loaded into the ListView (using the strTable variable).

    • If no table/query was selected, the ListView is empty, and the procedure exits without doing anything.

  5. Result

    • After processing all records, the form is closed.

    • Next time the form is opened, the ListView is populated from the Employees query, sorted on the ID field.

    • Because the ID values were updated with the last known order, and the data will appear in exactly the same sequence as when the form was last closed.

Windows Explorer-like sorting Method.

How Column Sorting Works

  • When the user clicks a column header, the ListView1_ColumnClick event fires.

  • We detect which column was clicked from the event argument (ColumnHeader.Index).

  • The code then checks whether that column is already the current sort column:

    • If yes → toggle between Ascending and Descending.

    • If no → set it as the new sort column (default to Ascending).

  • Finally, the ListView is refreshed with the new sort order.

Private Sub ListView1_ColumnClick(ByVal ColumnHeader As Object)
' When a ColumnHeader object is clicked, the ListView control is
' sorted by the subitems of that column.

With Me.ListView1
' Set the SortKey to the Index of the ColumnHeader - 1
    .SortKey = ColumnHeader.Index - 1
    
 If .SortOrder = lvwAscending Then
    .SortOrder = lvwDescending
 Else
    .SortOrder = lvwAscending
 End If
 ' Set Sorted to True to sort the list.
     .Sorted = True
End With
End Sub

Behavior

  • First, click on a column → sorts ascending.

  • Second, click on the same column → sorts descending.

  • Clicking a different column resets to ascending sort on that column.

Important Notes on Sorting Behavior

  1. Text-based Sorting Only

    • In the ListView control, every column value—whether it represents numbers, dates, or text—is stored as Text.

    • This is because the ListItems.Add()  ListSubItems.Add() Methods use the third parameter (Text) as the displayed value.

    • As a result, all comparisons during sorting are performed as string comparisons.

      • Example: "100" will sort before "2", since "1" comes before "2" in text order.

  2. Persistence of Sorted Order (Windows Explorer Behavior)

    • In Windows Explorer, when you sort a folder by name, size, or date, the system remembers your choice.

    • The next time you open the same folder, the list is automatically shown in that last sorted order.

  3. Implementing Similar Behavior in Access

    • By using the Form_Unload() event procedure, the ListView’s current sorted order is captured before the form closes.

    • Each ListItem’s index number is saved back into the ID field of the underlying table (Employees).

    • Since, the EmployeesQ Query always sorts on the ID field, the next time the form is opened, the ListView displays the data in the same order that the user last arranged (either by Drag & Drop or Column Sorting).


Demo Database

  • The sample database provided contains two forms:

    1. Form 1: Demonstrates opening different tables and queries in the ListView for datasheet-style viewing.

    2. Form 2: Focuses on the EmployeesQ query, allowing drag, drop, sort, and save functionality, so that the user’s preferred order is preserved between sessions.



  1. ActiveX ListView Control Tutorial-01.
  2. ListView Control Tutorial-02.
  3. Assigning Images To ListView Items.
  4. ListView Control Drag-Drop Sort Events
  5. ListView Control With MS-Access TreeView
  6. TreeView/ListView Controls Drag-Drop Events
Share:

Assigning Images To ListView Items Tutorial-03

The ImageList ActiveX Control.

To assign images to the ListView control, we need the support of another ActiveX control: the ImageList control. You may have noticed how Windows Explorer displays icons—such as folders in a closed state, which change to an open folder when clicked, along with different icons for various file types. While the ListView control does not provide that level of flexibility, it does allow us to display icon images in Column Headers, List Items, and ListSubItems when populating their contents. The Sample Demo Images.

Sample Preview

The following image shows an example of the Northwind Trading Employees listing, where each employee’s details are displayed in the ListView control along with their small photo icons. These images are assigned through the ImageList control and linked to the ListView items, making the data both informative and visually appealing.

Note: Using larger image sizes will automatically increase the row height of the ListView records, so you can display bigger photos if required.

The following sample image shows the ListView control (displayed in the right-side panel) used together with the TreeView control. The TreeView ActiveX control was already introduced in an earlier tutorial series. For quick reference, you can find the list of TreeView Control Tutorial Series links at the bottom of this page.

In the above picture, icon images have been applied to all data columns as well as the column header labels to demonstrate how images can be displayed in the ListView control.

On the left panel, the TreeView control nodes show the familiar folder icons in open and closed states. These behave differently from the ListView items: when a TreeView node is clicked, the open-folder image is displayed; clicking the same node again reverts it to the closed-folder image.

The ListView Control Programming Tutorial Series.

I hope you have already gone through the ListView Control Tutorial Sessions 1 and 2 and are now ready to continue with this new episode on using the ImageList Control along with the ListView Control.

For your convenience, the links to the earlier tutorials are provided below. I encourage you to review them before proceeding, as they cover some of the basic concepts of the ListView Control along with supporting VBA code. This background will put you in a better position to follow along and clearly understand the new features we are adding in this session.

  1. ListView Control Tutorial-01.

  2. ListView Control Tutorial-02.

Source Data and Demo Form.

  1. Let’s begin by creating a new Form and preparing the Employees Table for our ListView Control demo project.

    1. Import the Employees Table from the NorthWind.accdb sample database.

    2. Create a new SELECT Query using the SQL statement provided below.

    3. Save this query with the name EmployeesQ.

    SELECT [TitleOfCourtesy] & " " & [FirstName] & " " & [LastName] AS [Employee Name], 
    Employees.EmployeeID, 
    Employees.Title, 
    Employees.HireDate, 
    Employees.Address, 
    Employees.City, 
    Employees.Region, 
    Employees.PostalCode, 
    Employees.Country, 
    Employees.HomePhone, 
    Employees.Extension, 
    Employees.Notes
    FROM Employees;
    
  2. If your Employees Table structure is different, don’t worry. For the first column value, I have combined three fields together to form [Employee Name]. For the remaining columns, you can use whatever fields you have—include all of them or just a few, and in any order you prefer.

    Steps to Set Up the Form

    1. Create a new Form and open it in Design View.

    2. From the ActiveX Controls List, insert a Microsoft ListView Control.

    3. From the same list, insert a Microsoft ImageList Control.

    4. Resize the ListView Control as shown in the sample image of the form (provided earlier).

    5. Move the ImageList Control to the top-right corner of the ListView control, as shown in the demo image. You can also place it anywhere convenient on the form.

    Note: The ImageList Control will not be visible when the form is opened in Normal View; it appears only in Design View for configuration.

  3. Select the ListView Control and open its Property Sheet.

    • Change the Name property to ListView1.

  4. Select the ImageList Control, open its Property Sheet, and

    • Change the Name property to ImageList0.

    Important: Both the ListView and ImageList controls come with their own dedicated Property Sheets. Some of their property names and values may also appear in the Access Property Sheet, but updates made there may not always reflect correctly in the controls themselves. For reliable results, always make changes in each control’s own Property Sheet.

    ListView Control Property Sheet.

  5. Right-click on the ListView Control, point to the ListViewCtrl Object option from the shortcut menu, and then select Properties.

    The General tab of the ListView Control Property Sheet will appear, as shown in the image below. 

  6. Change the property values on the General tab as shown in the image above.

    Next, we will begin by loading the Employees data into the ListView Control.

    The Form Module VBA Code

  7. Copy and Paste the following VBA Code into the Form's Class Module:

    Option Compare Database
    Option Explicit
    
    Dim lvwList As MSComctlLib.ListView
    Dim lvwItem As MSComctlLib.ListItem
    Dim ObjImgList As MSComctlLib.ImageList
    Dim db As DAO.Database
    Dim rst As DAO.Recordset
    
    
    Private Sub cmdClose_Click()
       DoCmd.Close acForm, Me.Name
    End Sub
    
    Private Sub Form_Load()
     Call LoadListView("EmployeesQ")
    End Sub
    
    Private Sub LoadListView(ByVal tblName As String)
        Dim strFldName As String
        Dim intCounter As Integer
        Dim j As Integer
        Dim strLabel As String
    
    'Assign ListView Control on Form to lvwList Object
    Set lvwList = Me.ListView1.Object
    'Set ObjImgList = Me.ImageList0.Object
        
    'Assign Form Header labels Caption Text
     strLabel = UCase(tblName) & " " & "IN LISTVIEW CONTROL - TUTORIAL-03"
     Me.Label8.caption = strLabel
     Me.Label9.caption = strLabel
     
     With lvwList
        '.Icons = ObjImgList
        '.SmallIcons = ObjImgList
        '.ColumnHeaderIcons = ObjImgList
        .Font = "Verdana"
        .Font.Size = 10
        .Font.Bold = True
     End With
     
     Set db = CurrentDb
     Set rst = db.OpenRecordset(tblName, dbOpenSnapshot)
     
     'Create Column Headers for ListView
     With lvwList
        .ColumnHeaders.Clear 'initialize header area
        For j = 0 To rst.Fields.Count - 1
            strFldName = rst.Fields(j).Name
       'Syntax:
       '.ColumnHeaders.Add Index, Key, Text, Width, Alignment, Icon
            .ColumnHeaders.Add , , strFldName, iif(j=0,3200,2000)
        Next
     End With
     
     'Initialize ListView Control
      While lvwList.ListItems.Count > 0
            lvwList.ListItems.Remove (1)
      Wend
    
     With lvwList
     Do While Not rst.EOF And Not rst.BOF
    
       'Syntax  .ListItems.Add(Index, Key, Text, Icon, SmallIcon)
            Set lvwItem = .ListItems.Add(, , CStr(Nz(rst.Fields(0).Value, "")))
            
       'Add next columns of data as sub-items of ListItem
            With lvwItem
       'Syntax     .Add Index,Key,Text,Report Icon,TooltipText
             For j = 1 To rst.Fields.Count - 1
                .ListSubItems.Add , , CStr(Nz(rst.Fields(j).Value, ""))
             Next
    
           End With
           rst.MoveNext
    Loop
    rst.Close
        'reset lvwItem object
        Set lvwItem = Nothing
    End With
    
    Set rst = Nothing
    Set db = Nothing
    End Sub
    
    

    Note:  The Red-Colored VBA lines of the ImageList control are commented out from executing for the time being, and we will enable them shortly.

  8. Save your Form with the Name frmEmployees.

  9. Open the Form in Normal View. 

    The EmployeesQ Query Records Listing will look like the following Image:

  10. Review of the VBA Code

    We have already reviewed most of the above VBA code in ListView Control Tutorial Sessions 01 and 02, with only a few additions specific to the ImageList Control. These include its declaration, initialization, and a few lines for setting the Font Name, Font Size, and Font Style.

    Another important change is in the LoadListView() procedure. In this version, the procedure accepts a Table or Query Name as a parameter. All query types—except Action Queries—as well as Access Tables and Linked Tables, are valid inputs. The specified Table or Query name is supplied when the program is called from the Form_Load() Event Procedure.

    All field names from the given Table or Query are used as Column Header Labels (the third parameter) in the ColumnHeaders.Add() method. The Index and Key parameters (first and second) are not used here, as the system automatically assigns Index values in sequence.

    • The fourth parameter specifies the column width in pixels. In our example, the first column is set to 3200 pixels to accommodate the Employee Name, while all other columns are set to 2000 pixels.

    • Alignment and Icon parameters for column headers are not used. By default, column headers are left-aligned. The available alignment options are:

      • 0 - lvwColumnLeft

      • 1 - lvwColumnRight

      • 2 - lvwColumnCenter

    You can view these options on the Column Headers Tab of the ListView Control Property Sheet:

    1. Click the Insert Column button and enter a temporary column name.

    2. Open the Alignment property to view the available options.

    3. Click Remove Column to delete the temporary column.

    Note: If you prefer to add Column Header Labels manually, instead of loading field names through VBA code, you can type them directly here. They will then appear as column headers when the data is displayed.

    A sample view of the Icon image on the left side of the header column names can be seen in the second demo image in the right-side panel at the top of this page.

    For the data itself:

    • The first column (Employee Name from the EmployeesQ query) is assigned to the ListItems.Text property using the .Add method. Here too, the Index and Key parameters are omitted—the system automatically inserts Index numbers as serial values.

    • From the second field onward, column values are added through the ListSubItems.Add() method of the ListView Control.

    Note: All values are stored as Text in ListItems.Text and ListSubItems.Text, regardless of their original data type in the source Table/Query. To prevent errors, the code checks for Null values and converts them to text using the CStr() function.

    The ImageList control.

    In the main program, the ImageList Control initialization statements have been temporarily commented out. These lines are highlighted in red in the code segment below. We will revisit, explain, and enable them once we are ready to proceed with uploading images into the ImageList Control.

    'Assign ListView Control on Form to lvwList Object
    Set lvwList = Me.ListView1.Object
    'Set ObjImgList = Me.ImageList0.Object
        
    'Assign Form Header labels Caption Text
     strLabel = UCase(tblName) & " " & "IN LISTVIEW CONTROL - TUTORIAL-03"
     Me.Label8.caption = strLabel
     Me.Label9.caption = strLabel
     
     With lvwList
        '.Icons = ObjImgList
        '.SmallIcons = ObjImgList
        '.ColumnHeaderIcons = ObjImgList
        .Font = "Verdana"
        .Font.Size = 10
        .Font.Bold = True
     End With
     

    The first red-highlighted statement initializes the ObjImgList object with the ImageList0 control placed on the frmEmployees form. Before making changes to the code, let’s first explore the available options for uploading images into the ImageList Control.

    About Uploading Images.

    The next step is to upload some sample images into the ImageList Control. This can be done in one of two ways.

    Before starting, prepare at least two small images in any popular format—such as JPG, JPEG, BMP, or PNG—with BMP being the preferred type. The ImageList Control supports the following standard image sizes (available on the General tab of its Property Sheet): 16×16, 32×32, 48×48 pixels, or a Custom size.

    To configure this:

    1. Right-click on the ImageList Control,

    2. Highlight ImageListCtrl Object,

    3. Select Properties,

    4. Then, on the General tab, choose your desired image size before uploading any images.

    If you have larger images and want to keep their original size, select the Custom option. Otherwise, choosing a predefined size will automatically scale the images, which may reduce their quality. Keep in mind that using very large images will increase the row height when displayed in the ListView Control.

    For best results, icon-style images are ideal. However, you should experiment with different sizes—large, small, and very small—along with the available options to determine what works best for your project.

    You can upload images into the ImageList Control in one of the following two ways:

    1. Upload Images from disk through VBA Procedure.

    The sample VBA Procedure will look like the Code Segment given below, taken from the  TreeView Control Tutorial:

      
      Set objImgList = Me.ImageList0.Object
      objImgList.ListImages.Clear
      
    strFolder = "D:\Access\TreeView\"
    With objImgList
        With .ListImages
             .Add Index:=1, Key:="FolderClose", Picture:=LoadPicture(strFolder & "folderclose2.bmp")
             .Add Index:=2, Key:="FolderOpen", Picture:=LoadPicture(strFolder & "folderopen2.bmp")
             .Add Index:=3, Key:="ArrowHead", Picture:=LoadPicture(strFolder & "arrowhead.bmp")
        End With
    End With
    
    With tvw 'TreeView Control
        .ImageList = objImgList 'assign imagelist Object to TreeView Imagelist Property
    End With

    The first statement initializes the objImgList object with the ImageList0 control on the form.

    The next statement clears any existing images in the ImageList control, ensuring it is ready for new uploads from disk. For this method to work consistently, the required image files must always be available on the disk.

    The method objImgList.ListImages.Add()  is then used to upload images from disk. When using named parameters, the parameter values can be provided in any order. For example:

    • Index := 1 can appear at the end of the line,

    • Key := "FolderClose" can be listed first,

    and so on.

    However, if parameter names are omitted, the parameters must be supplied in the following order:

             .Add 1, "FolderClose", LoadPicture(strFolder & "folderclose2.bmp")

    To display an image in the ListView control, you can reference it either by using the Image Index Number (e.g., 1) or by specifying the Key value (e.g., "FolderClose") as the Icon or SmallIcon parameter in the ListItems.Add() method.

    We used this same approach earlier in the TreeView Control Tutorial. You may refer to that page and download the demo database for reference.

    This method loads the images into the ImageList object instance in memory, without altering the physical ImageList control on the form. However, it is important to note that the source images on disk must always be available every time frmEmployees is opened.

    2. Uploading Images from disk manually.

    This is a one-time setup task: locating the images on disk and uploading them into the ImageList Control.

    The key advantage of this method is that once images are uploaded into the ImageList Control, they remain embedded in the control. You won’t need to reload them from disk each time the form is opened. Moreover, the ImageList control—with the images included—can be copied and reused in other projects, or even shared with colleagues, eliminating the need for duplicate image setup.

    For this demonstration, let’s use the manual upload method, which is the more reliable approach. Prepare two samples .bmp images with a resolution of 50 x 50 pixels (e.g., image1.bmp, image2.bmp) and keep them ready in a folder, such as D:\Access\, for reference.

    Now, follow these steps:

    1. Open frmEmployees in Design View.

    2. Right-click on the ImageList Control, highlight ImageListCtrl Object, and select Properties.

    3. On the General tab, select the Custom option to retain the original resolution of the uploaded images.

    At this point, the General tab of the ImageList Control will appear as shown in the image below.

    The Images tab View of the ImageList Control

    Note: After testing uploaded images in the ListView control, if you wish to try a different size option (48×48, 32×32, or 16×16), you must first remove all existing images. Then, return to the General tab, select the new size option, and upload the images again. The uploaded images will automatically be resized to match the selected option.

    In the sample below, two images have been uploaded using the Insert Picture command button. The first image is currently selected, shown in a slightly raised position. The Index control displays the value:1, while the Key textbox shows the text First. The Index value is generated automatically, but the Key value must be entered manually. Use a meaningful Key name that is easy to remember and logically relates to the data.

    Both the Index number and the Key text can be used in the Icon or SmallIcon parameters of the ListItems.Add() method.

    If you plan to rely on Index numbers, be sure the image upload sequence matches the data sequence in the ListView (for example, each employee’s name aligns correctly with their photo). However, a more practical approach is to use Key text values—such as an employee’s first name—since they are easier to associate directly with records. For generic icons, descriptive Key names (e.g., FolderClosed, FolderOpen) provide clarity about their purpose.

    Steps to upload images:

    1. Open the Images tab of the ImageList Control.

    2. Click Insert Picture, browse the file  'D:\Access\Image1.bmp' to select it, and click Open to upload the image.

    3. In the Key textbox, type a unique Key value (e.g., First).

    4. Repeat steps 2–3 for the second image (e.g., D:\Access\Image2.bmp), assigning it another unique Key value.

    Your ImageList Control is now configured with sample images and ready to display them in the ListView Control.

Assigning ImageList Object to ListView Object Properties.

To display images in the ListView Control, the following ListView Object properties must be linked to the ImageList Object:

  • ListView.ColumnHeaderIcons

  • ListView.Icons

  • ListView.SmallIcons

The next step is to assign the ImageList Object to the ListView Control through these properties in VBA code:

  • lvwList.ColumnHeaderIcons

  • lvwList.Icons

  • lvwList.SmallIcons

This must be done before you can use image references (Index or Key values) in the following methods:

  • ColumnHeaders.Add()

  • ListItems.Add()

  • ListSubItems.Add()

We have already added the necessary VBA statements in the LoadListView() procedure of the main program, but they are currently commented out. To activate them:

  1. Open the LoadListView() procedure.

  2. Locate the four lines of code (highlighted earlier in red).

  3. Remove the comment symbol (') at the beginning of each line to enable them.

  4. Update the code to include the appropriate Icon Index values in the method parameters.

For example, modify the following statements (originally shown in red in the main program) to use Icon Index numbers 1 and 2 for the Icon  SmallIcon parameters:

' Example modification in LoadListView() Set lvwList.ColumnHeaderIcons = objImgList Set lvwList.Icons = objImgList Set lvwList.SmallIcons = objImgList lvwList.ListItems.Add , , "Employee 1", , 1 ' Icon Index = 1 lvwList.ListItems.Add , , "Employee 2", , 2 ' SmallIcon Index = 2

This ensures that images stored in the ImageList Control are correctly displayed alongside the ListView items.

 With lvwList
 Do While Not rst.EOF And Not rst.BOF

   'Syntax  .ListItems.Add(Index, Key, Text, Icon, SmallIcon)
       ' Set lvwItem = .ListItems.Add(, , CStr(Nz(rst.Fields(0).Value,"")))
       'Change to 
         Set lvwItem = .ListItems.Add(, , CStr(Nz(rst.Fields(0).Value,"")), 1, 2)
        
   'Add next columns of data as sub-items of ListItem
        With lvwItem
   'Syntax     .Add Index,Key,Text,Report Icon,TooltipText
         For j = 1 To rst.Fields.Count - 1
           ' .ListSubItems.Add , , CStr(Nz(rst.Fields(j).Value, ""))
           'Change to           
             .ListSubItems.Add , , CStr(Nz(rst.Fields(j).Value, "")),,"Click"
         Next

       End With
       rst.MoveNext
Loop
rst.Close

Since we have only two images available, we will use the first image (Index = 1) as the Icon parameter and the second image (Index = 2) as the SmallIcon parameter.

  • The Icon image is displayed only when the ListView display option is set to 0 - lvwIcon.

  • The SmallIcon image is displayed in all other ListView display options.

In the ListSubItems.Add() method, we have not assigned any image reference. Instead, we used the next parameter to specify a Tooltip text "Click". This text will appear as a tooltip when the mouse pointer hovers over any column from the second column onward.

After making these code changes:

  1. Save the form frmEmployees.

  2. Open the form in Normal View.

  3. You should now see the ListView display similar to the sample image shown at the top of this page.

The SmallIcon will remain visible in all ListView display modes, except for 'lvwIcon', which uses the larger Icon image.

Check the following sample ListView screenshots of Employee data for reference.

0 - lvwIcon View

ListView Icon View

2 - lvwList View

The first sample image at the top of this page shows the 03 - lvwReport view.
This is the only view that displays all column values in a datasheet-like format.

To explore other views:

  1. Open the form frmEmployees in Design View.

  2. Select the ListView control and open its Property Sheet.

  3. Locate the View property.

  4. Change the setting to try out each option (0 - lvwIcon, 1 - lvwSmallIcon, 2 - lvwList, 3 - lvwReport).

  5. Save the form and open it in Normal View to see how the data is displayed in each case.


👉 This hands-on test helps you understand how the same data looks in different ListView display modes and which one best fits your application.

Download the Demo Database.

 

  1. Microsoft TreeView Control Tutorial
  2. Creating an Access Menu with a TreeView Control
  3. Assigning Images to TreeView Nodes
  4. Assigning Images to TreeView Nodes-2
  5. TreeView Control Checkmark Add Delete
  6. TreeView ImageCombo Drop-down Access
  7. Re-arrange TreeView Nodes By Drag and Drop
  8. ListView Control with MS-Access TreeView
  9. ListView Control Drag Drop Events
  10. TreeView Control With Sub-Forms
Share:

PRESENTATION: ACCESS USER GROUPS (EUROPE)

Translate

PageRank

Post Feed


Search

Popular Posts

Blog Archive

Powered by Blogger.

Labels

Forms Functions How Tos MS-Access Security Reports msaccess forms Animations msaccess animation Utilities msaccess controls Access and Internet MS-Access Scurity MS-Access and Internet Class Module External Links Queries Array msaccess reports Accesstips WithEvents msaccess tips Downloads Objects Menus and Toolbars Collection Object MsaccessLinks Process Controls Art Work Property msaccess How Tos Combo Boxes Dictionary Object ListView Control Query VBA msaccessQuery Calculation Event Graph Charts ImageList Control List Boxes TreeView Control Command Buttons Controls Data Emails and Alerts Form Custom Functions Custom Wizards DOS Commands Data Type Key Object Reference ms-access functions msaccess functions msaccess graphs msaccess reporttricks Command Button Report msaccess menus msaccessprocess security advanced Access Security Add Auto-Number Field Type Form Instances ImageList Item Macros Menus Nodes RaiseEvent Recordset Top Values Variables Wrapper Classes msaccess email progressmeter Access2007 Copy Excel Export Expression Fields Join Methods Microsoft Numbering System Records Security Split SubForm Table Tables Time Difference Utility WScript Workgroup database function msaccess wizards tutorial Access Emails and Alerts Access Fields Access How Tos Access Mail Merge Access2003 Accounting Year Action Animation Attachment Binary Numbers Bookmarks Budgeting ChDir Color Palette Common Controls Conditional Formatting Data Filtering Database Records Defining Pages Desktop Shortcuts Diagram Disk Dynamic Lookup Error Handler External Filter Formatting Groups Hexadecimal Numbers Import Labels List Logo Macro Mail Merge Main Form Memo Message Box Monitoring Octal Numbers Operating System Paste Primary-Key Product Rank Reading Remove Rich Text Sequence SetFocus Summary Tab-Page Union Query User Users Water-Mark Word automatically commands hyperlinks iSeries Date iif ms-access msaccess msaccess alerts pdf files reference restore switch text toolbar updating upload vba code