Question Set Listbox Checked problem on load, activate, shown event

goldford

Member
Joined
May 6, 2009
Messages
12
Programming Experience
1-3
Hi,

I've been having a problem setting certain items in a listbox as checked when the form is loaded. I have tried putting the code in the form_activate, form_load, and form_shown events and each still crashes when it encounters:

VB.NET:
Dim m As Integer = 0
Me.lstLineLayers.SetItemChecked(m, True)

I see the issue discussed here: CheckedListBox SetItemChecked method not working. - microsoft.public.dotnet.framework.windowsforms | Google Groups but I would like to have certain listbox items checked when the form appears based on some default settings. Does anyone know how to resolve this issue?
 
No, my checklistbox is not databound. I am translating from vb6 at the moment and have no experience with databinding and haven't a clue how to implement it.

A button in embedded in the GIS software ArcMap will open a form. It reads the layers present and loads their names into a listbox. An object with default layers is also passed to the form and after the names are loaded, they are all cycled through and checked for a match with the default names. If they match they are set as checked.

Presently this code runs in form.load:

VB.NET:
' load all layers in TOC to the lstbox
        For i = 0 To pMap.LayerCount - 1
            pFeatureLayer = pMap.Layer(i)
            If pFeatureLayer.FeatureClass.ShapeType = esriGeometryType.esriGeometryPolyline Then
                lstLineLayers.Items.Add(pMap.Layer(i).Name)
            ElseIf pFeatureLayer.FeatureClass.ShapeType = esriGeometryType.esriGeometryPolygon Then
                lstPolyLayers.Items.Add(pMap.Layer(i).Name)
            End If
        Next


VB.NET:
sPolyLayer = m_DFOExt.pPropset.GetProperty("IncPoly" + k.ToString) ' get poly layer
m = 0 ' loop to set currently selected
                        For m = 0 To lstPolyLayers.Items.Count - 1                ' for each item in list
                            If sPolyLayer = lstPolyLayers.Items.Item(m) Then      ' if the two match
                                lstPolyLayers.SetItemChecked(m, True)             ' set it selected
                            End If
                        Next

There is an exception at .setitemchecked. This happens when the code is put in form.shown and form.activated as well. It also is thrown if I try to set the checked state as I add the items to the list using this:

VB.NET:
lstLineLayers.Items.Add(pMap.Layer(i).Name, true)
 
1. Rather than just say "it crashes" or "there is an exception", can you please tell us exactly what the error is - we arent mind readers :D

2. I would turn Option Strict On in your code. The line

VB.NET:
If sPolyLayer = lstPolyLayers.Items.Item(m) Then

concerns me, especially as you havent shown us the definition line for sPolyLayer. I assume it is a string variable, but I am having to guess :)

3. Can you please post the code for the parent form that calls this form?
 
Here is the code for the command that calls the form.

VB.NET:
Imports System.Runtime.InteropServices
Imports System.Drawing
Imports ESRI.ArcGIS.ADF.BaseClasses
Imports ESRI.ArcGIS.ADF.CATIDs
Imports ESRI.ArcGIS.Framework
Imports ESRI.ArcGIS.ArcMapUI

<ComClass(OpenOptions.ClassId, OpenOptions.InterfaceId, OpenOptions.EventsId), _
 ProgId("DFOFishBarriersDST.OpenOptions")> _
Public NotInheritable Class OpenOptions
    Inherits BaseCommand

#Region "COM GUIDs"
    ' These  GUIDs provide the COM identity for this class 
    ' and its COM interfaces. If you change them, existing 
    ' clients will no longer be able to access the class.
    Public Const ClassId As String = "666b9a12-343b-4022-8576-78cee6c118dd"
    Public Const InterfaceId As String = "4db38fff-d896-41cb-a515-a67da9061eaf"
    Public Const EventsId As String = "32a00f2b-975e-44e3-9231-bba01ddaba87"
#End Region

#Region "COM Registration Function(s)"
    <ComRegisterFunction(), ComVisibleAttribute(False)> _
    Public Shared Sub RegisterFunction(ByVal registerType As Type)
        ' Required for ArcGIS Component Category Registrar support
        ArcGISCategoryRegistration(registerType)

        'Add any COM registration code after the ArcGISCategoryRegistration() call

    End Sub

    <ComUnregisterFunction(), ComVisibleAttribute(False)> _
    Public Shared Sub UnregisterFunction(ByVal registerType As Type)
        ' Required for ArcGIS Component Category Registrar support
        ArcGISCategoryUnregistration(registerType)

        'Add any COM unregistration code after the ArcGISCategoryUnregistration() call

    End Sub

#Region "ArcGIS Component Category Registrar generated code"
    Private Shared Sub ArcGISCategoryRegistration(ByVal registerType As Type)
        Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
        MxCommands.Register(regKey)

    End Sub
    Private Shared Sub ArcGISCategoryUnregistration(ByVal registerType As Type)
        Dim regKey As String = String.Format("HKEY_CLASSES_ROOT\CLSID\{{{0}}}", registerType.GUID)
        MxCommands.Unregister(regKey)

    End Sub

#End Region
#End Region


    Private m_application As IApplication

    ' A creatable COM class must have a Public Sub New() 
    ' with no parameters, otherwise, the class will not be 
    ' registered in the COM registry and cannot be created 
    ' via CreateObject.
    Public Sub New()
        MyBase.New()

        ' TODO: Define values for the public properties
        MyBase.m_category = "DFO Maritimes Fish Barrier DST"  'localizable text 
        MyBase.m_caption = "Opens an option menu"   'localizable text 
        MyBase.m_message = "Opens an option"   'localizable text 
        MyBase.m_toolTip = "" 'localizable text 
        MyBase.m_name = "DFOMDST_OpenOptions"  'unique id, non-localizable (e.g. "MyCategory_ArcMapCommand")

        Try
            'TODO: change bitmap name if necessary
            Dim bitmapResourceName As String = Me.GetType().Name + ".bmp"
            MyBase.m_bitmap = New Bitmap(Me.GetType(), bitmapResourceName)
        Catch ex As Exception
            System.Diagnostics.Trace.WriteLine(ex.Message, "Invalid Bitmap")
        End Try


    End Sub


    Public Overrides Sub OnCreate(ByVal hook As Object)
        If Not hook Is Nothing Then
            m_application = CType(hook, IApplication)

            'Disable if it is not ArcMap
            If TypeOf hook Is IMxApplication Then
                MyBase.m_enabled = True
            Else
                MyBase.m_enabled = False
            End If
        End If

        ' TODO:  Add other initialization code
    End Sub

    Public Overrides Sub OnClick()
        'TODO: Add OpenOptions.OnClick implementation
        Dim MyForm As New DFOFishBarriersDST.Options

        If MyForm.Form_Initialize(m_application) Then
            MyForm.ShowDialog()
        End If

    End Sub
End Class

Here is the full code for the load event:

VB.NET:
Private Sub Options_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        
        Dim k As Integer = 0                ' loop counter
        Dim j As Integer = 0                ' loop counter
        Dim m As Integer = 0                ' another loop counter
        Dim sPolyLayer As String            ' a polygon layer saved in stream
        Dim sLineLayer As String            ' a line layer saved in stream

        Dim pMxDoc As IMxDocument
        Dim pMap As IMap

        ' hook into ArcMap
        pMxDoc = m_app.Document
        pMap = pMxDoc.FocusMap

        Dim pFeatureLayer As IFeatureLayer
        Dim i As Integer

        ' Default to the first tab
        TabControl1.SelectTab(0)

        ' load all layers in TOC to the lstbox
        For i = 0 To pMap.LayerCount - 1
            pFeatureLayer = pMap.Layer(i)
            If pFeatureLayer.FeatureClass.ShapeType = esriGeometryType.esriGeometryPolyline Then
                lstLineLayers.Items.Add(pMap.Layer(i).Name)
            ElseIf pFeatureLayer.FeatureClass.ShapeType = esriGeometryType.esriGeometryPolygon Then
                lstPolyLayers.Items.Add(pMap.Layer(i).Name)
            End If
        Next

        ' Read the properties saved in the extension, if they are saved
        Try
            If m_DFOExt.bLoaded = True Then
                m_sDirection = m_DFOExt.pPropset.GetProperty("direction")
                m_iOrderNum = m_DFOExt.pPropset.GetProperty("ordernum")  
                m_bMaximum = m_DFOExt.pPropset.GetProperty("maximum")
                m_bConnectTab = m_DFOExt.pPropset.GetProperty("connecttab")
                m_bDBF = m_DFOExt.pPropset.GetProperty("bDBF")
                m_sGDB = m_DFOExt.pPropset.GetProperty("sGDB")
                m_sPrefix = m_DFOExt.pPropset.GetProperty("TabPrefix")
                m_bDockWin = m_DFOExt.pPropset.GetProperty("DockWin")
                m_bTotalImp = m_DFOExt.pPropset.GetProperty("TotalImp")

                m_iPolysCount = m_DFOExt.pPropset.GetProperty("numPolys")
                Dim HabLayerObj As New LayerToAdd(Nothing, Nothing, Nothing) ' layer to hold parameters to send to property

                ' match any of the polygon layers saved in stream to those in listboxes and select
                If m_iPolysCount > 0 Then
                    For k = 0 To m_iPolysCount - 1
                        sPolyLayer = m_DFOExt.pPropset.GetProperty("IncPoly" + k.ToString) ' get poly layer
                        With HabLayerObj
                            .Layer = sPolyLayer
                            .ClsField = m_DFOExt.pPropset.GetProperty("PolyClassField" + k.ToString)
                            .QuanField = m_DFOExt.pPropset.GetProperty("PolyQuanField" + k.ToString)
                        End With

                        ' Load that object into the list
                        m_PLayersFields.Add(HabLayerObj)  
                        'm = 0 ' loop to set currently selected
                        'For m = 0 To lstPolyLayers.Items.Count - 1                ' for each item in list
                        '    If sPolyLayer = lstPolyLayers.Items.Item(m) Then      ' if the two match
                        '        lstPolyLayers.SetItemChecked(m, True)             ' set it selected
                        '    End If
                        'Next
                    Next
                End If

                m_iLinesCount = m_DFOExt.pPropset.GetProperty("numLines")
                ' match any of the line layers saved in stream to those in listboxes and select
                If m_iLinesCount > 0 Then
                    For j = 0 To m_iLinesCount - 1
                        sLineLayer = m_DFOExt.pPropset.GetProperty("IncLine" + j.ToString) ' get line layer

                        With HabLayerObj
                            .Layer = sLineLayer
                            .ClsField = m_DFOExt.pPropset.GetProperty("LineClassField" + j.ToString)
                            .QuanField = m_DFOExt.pPropset.GetProperty("LineQuanField" + j.ToString)
                        End With

                        ' add to the module level list
                        m_LLayersFields.Add(HabLayerObj)

                        m = 0
                        For m = 0 To lstLineLayers.Items.Count - 1                ' for each item in list
                            If sLineLayer = lstLineLayers.Items.Item(m) Then
                                ' if the two match
                                Me.lstLineLayers.SetItemChecked(m, True)
                                'lstLineLayers.s()
                            End If
                        Next
                    Next
                End If

            End If
        Catch ex As Exception
            System.Windows.Forms.MessageBox.Show(ex, "Initialize")
            Exit Sub
        End Try
End Sub

The variable you mentioned is a string. I do not have any feedback on the error, I don't know if I have my exception handling set up properly.
 
VB.NET:
Catch ex As Exception
            System.Windows.Forms.MessageBox.Show(ex, "Initialize")
            Exit Sub
        End Try

With Option Strict On, my IDE shows :-

VB.NET:
Value of type 'System.Exception' cannot be converted to 'String'

So you will need to change it to :-

VB.NET:
Catch ex As Exception
            System.Windows.Forms.MessageBox.Show(ex.message, "Initialize")
            Exit Sub
        End Try

This should help to identify the problem - but obviously wont fix it yet :)
 
Thank you for your help!

Now I'm able to see the error: "Object reference not set to an instance of an object"

I have read other people having the same problem. Just setting items in a check listbox as "checked" within the load or activate events will cause this error. Has anyone found a viable solution to this yet - so desired items in a list are checked when a form loads??
 
You have commented out the lstPolyLayers.SetItemChecked line. Does the exception still occur after this? What happens if you comment out this line :-

VB.NET:
Me.lstLineLayers.SetItemChecked(m, True)
 
Commenting out this line does prevent the error from occurring.

I believe the problem is that the item in the listbox cannot be set as "Checked" because it has not been fully initialized and does not exist yet. I have tried putting this code in the 'activate' and 'shown' event code, however, and still get the error.
 
Setting items to be checked in the Load event seems to work for me :-

VB.NET:
Option Explicit On
Option Strict On

Public Class Form1

    Public Sub New()
        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        clbTest.Items.Clear()
        clbTest.Items.Add("TEST 1")
        clbTest.Items.Add("TEST 2")
        clbTest.Items.Add("TEST 3")
    End Sub

    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        clbTest.SetItemChecked(1, True)
        clbTest.SetItemCheckState(2, CheckState.Checked)
    End Sub

End Class

Try moving the code from the Load event into the New event.
What's happening in "Form_Initialize" ?
 
I have some trouble loading the items in the New event. The form is initialized by a button in ArcMap (ESRI ArcGIS software - 9.2). The button passes a reference to the current map document to the form:

VB.NET:
Public Overrides Sub OnCreate(ByVal hook As Object)
        If Not hook Is Nothing Then
            m_application = CType(hook, IApplication)

            'Disable if it is not ArcMap
            If TypeOf hook Is IMxApplication Then
                MyBase.m_enabled = True
            Else
                MyBase.m_enabled = False
            End If
        End If
        pMxDoc = CType(m_application.Document, ESRI.ArcGIS.ArcMapUI.IMxDocument)

End Sub

    Public Overrides Sub OnClick()
        'TODO: Add OpenOptions.OnClick implementation
        Dim MyForm As New DFOFishBarriersDST.Options

        If MyForm.Form_Initialize(m_application) Then
MyForm.ShowDialog()
End If
End Sub

The form_initialize handles this reference:

VB.NET:
Public Function Form_Initialize(ByVal m_application As ESRI.ArcGIS.Framework.IApplication) As Boolean

        Dim pMap As ESRI.ArcGIS.Carto.IMap
        Dim pLayer As ESRI.ArcGIS.Carto.ILayer
        Dim pFLayer As ESRI.ArcGIS.Carto.IFeatureLayer2
        Dim pGeoDataset As ESRI.ArcGIS.Geodatabase.IGeoDataset

        Try
            m_app = m_application
            pMxDoc = CType(m_app.Document, ESRI.ArcGIS.ArcMapUI.IMxDocument)

            Return True

        Catch ex As Exception
            System.Windows.Forms.MessageBox.Show(ex, "Initialize")
            Return False
        End Try
    End Function

I tried putting the code to add items in form_initialize and the code to check an item in the listbox in form_load but the same exception as before arose.

I also tried adding items in the New event of the form, then checking the item in the listbox in the form_load event and the same exception occurred.

There is some discussion about this in a data-binding context here, but I do not know how their workarounds could apply here: CheckedListBox SetItemChecked method not working. - microsoft.public.dotnet.framework.windowsforms | Google Groups
 
I also tried your code you posted, using a button to call the form and got the this error:

"The value of argument 'value' (-1) is invalid for Enum type 'CheckState'.
Parameter name: value"

The error happens only when I try to set the checkstate with boolean 'true' or 'false' - when I use 'windows.form.checkstate.checked' it works. However, this does not solve my problem - I still get the error when I make the change to my code:

"Object reference not set to an instance of an object"
 
The error happens only when I try to set the checkstate with boolean 'true' or 'false' - when I use 'windows.form.checkstate.checked' it works.

That's because TRUE and FALSE are not members of CheckState. If it's throwing an error, that's because you still havent got Option Strict On - it shouldnt compile, giving the error "Option Strict On disallows implicit conversions from 'Boolean' to 'System.Windows.Forms.CheckState'"

I have some trouble loading the items in the New event. The form is initialized by a button in ArcMap (ESRI ArcGIS software - 9.2). The button passes a reference to the current map document to the form:

Did you try overloading the New event to pass the reference you require?

I still cant see that this is a problem with the CheckedListBox items. For example, you are comparing a String to an Object - which cant help. Your code should read :-

VB.NET:
If sLineLayer = lstLineLayers.Items.Item(m).ToString then

I know it may not correct the problem, but your code definitely has 'flaws'.

Have you tried checking the value of m when it throws the error? How many items are there in lstLineLayers? What does sLineLayer contain?

Separately, you dont appear to be disposing of your form once you've closed it. Either dispose it, or change your code to :-

VB.NET:
      Using MyForm As New DFOFishBarriersDST.Options
        If MyForm.Form_Initialize(m_application) Then
            MyForm.ShowDialog()
        End If
      End Using
 
Back
Top