Solved

items.clear not working to clear listview?

Posted on 2004-09-29
4
221 Views
Last Modified: 2010-08-05
for some strange reason i can resize my form and clear the items yet every now and then it crashes tellin me "Object reference not set to an instance of an object"??

i have posted the code below but im not sure why it shouldnt work because it does for a litle while and then crashes afterwards.

Thanks
Gozza


here is the code:

-------------------------------------------------------------------------------------------------------------------

    Public PreviousVItemCount As String
    Public TestArray(40) As ListViewItem
    Public FormLoaded As Boolean = False

    Public Sub Populate()

        With lvwLibrary2

            Dim i As Integer
            Dim ColWidth As Integer
            Dim VitemCount As String

            For i = 0 To .Columns.Count - 1
                ColWidth += .Columns(i).Width
            Next

            If ColWidth > .Width Then
                VitemCount = (.Height - 39) / 14
            Else
                VitemCount = (.Height - 19) / 14
            End If

            If VitemCount.IndexOf(".") > 0 Then
                VitemCount = VitemCount.Substring(0, VitemCount.IndexOf("."))
            ElseIf VitemCount.IndexOf(".") = 0 Then
                VitemCount = 0
            End If


            If Not VitemCount = PreviousVItemCount Then

                scrollV.Maximum = TestArray.Length + 8

                    If .Items.Count > 0 Then
                        .Items.Clear()
                    End If

                For i = 0 To VitemCount - 1
                    Try
                        .Items.Add(TestArray(scrollV.Value + i).Clone)
                    Catch ex As Exception
                        MsgBox(ex.Message)
                    End Try
                Next

                PreviousVItemCount = VitemCount

            End If


        End With

    End Sub
    Public Sub Scroll()

        With lvwLibrary2
            If scrollV.Value < OldValue Then
                .Items(.Items.Count - 1).Remove()
                .Items.Insert(0, TestArray(scrollV.Value).Clone)

            ElseIf scrollV.Value > OldValue Then
                .Items(0).Remove()
                .Items.Add(TestArray(scrollV.Value).Clone)
            End If

            OldValue = scrollV.Value
        End With

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Populate()       'this works fine, only crashes when it resizes
    End Sub

    Private Sub scrollV_Scroll(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ScrollEventArgs) Handles scrollV.Scroll
        Scroll()
    End Sub

    Private Sub lvwLibrary2_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles lvwLibrary2.SizeChanged
        If FormLoaded Then
            Populate()
        End If
    End Sub

    Private Sub frmOptions_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim i As Integer
        For i = 0 To 40
            Dim item As New ListViewItem
            item.Text = "test - " & i
            item.SubItems.Add("test - " & i)
            TestArray(i) = item
        Next
        FormLoaded = True
    End Sub

---------------------------------------------------------------------------------------------------------------
0
Comment
Question by:gozza11
  • 2
4 Comments
 
LVL 2

Accepted Solution

by:
GohdanTheMoblin earned 500 total points
ID: 12186250
I'd like to know what line your code is crashing at, but here's my guess:

A ListViewItem is a reference type.  When you add item to TestArray(i), you are only adding a reference to the item.  When you call .Items.Clear(), you destroy the object that both the ListView and TestArray referenced, so now TestArray is an array of 41 (stupid VB array syntax means your array has 0 through 40 = 41 elements) references to Nothing.

This problem could be solved by changing the last line of the For loop in the Load handler to:
TestArray(i) = item.Clone()

Although for lots of ListViewItems this could get expensive.  The way I handle situations like this is to create a class that has a member for each item, and a method that returns a ListViewItem properly initialized.  This way, you keep an array of these objects, and you don't have to worry about cloning.
0
 

Author Comment

by:gozza11
ID: 12186786
ok that seems to have made things work, yet it crashed when it was trying to clear the items. but u said there is a better way to get the items into the array. can u please explain how?

thanks
goz
0
 
LVL 11

Expert Comment

by:ajaikumarr
ID: 12187322
Hai,

Check the below code... It's working great.

The problem with your code is Populate() function is running multiple times as it's called on lvwLibrary2_SizeChanged event. So i've added a boolean variable ivlLodingList to check whether populate() function is running if not it will get called.

Public Class SystemTray
    Inherits System.Windows.Forms.Form

#Region " Windows Form Designer generated code "

    Public Sub New()
        MyBase.New()

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

        'Add any initialization after the InitializeComponent() call

    End Sub

    'Form overrides dispose to clean up the component list.
    Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)
        If disposing Then
            If Not (components Is Nothing) Then
                components.Dispose()
            End If
        End If
        MyBase.Dispose(disposing)
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    Private WithEvents NotifyIcon1 As System.Windows.Forms.NotifyIcon
    Friend WithEvents ContextMenu1 As System.Windows.Forms.ContextMenu
    Friend WithEvents mnuShow As System.Windows.Forms.MenuItem
    Friend WithEvents mnuHide As System.Windows.Forms.MenuItem
    Friend WithEvents lvwLibrary2 As System.Windows.Forms.ListView
    Friend WithEvents Button1 As System.Windows.Forms.Button
    Friend WithEvents scrollV As System.Windows.Forms.VScrollBar
    Friend WithEvents ColumnHeader1 As System.Windows.Forms.ColumnHeader
    Friend WithEvents ColumnHeader2 As System.Windows.Forms.ColumnHeader
    <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()
        Me.components = New System.ComponentModel.Container
        Dim resources As System.Resources.ResourceManager = New System.Resources.ResourceManager(GetType(SystemTray))
        Me.NotifyIcon1 = New System.Windows.Forms.NotifyIcon(Me.components)
        Me.ContextMenu1 = New System.Windows.Forms.ContextMenu
        Me.mnuShow = New System.Windows.Forms.MenuItem
        Me.mnuHide = New System.Windows.Forms.MenuItem
        Me.lvwLibrary2 = New System.Windows.Forms.ListView
        Me.Button1 = New System.Windows.Forms.Button
        Me.scrollV = New System.Windows.Forms.VScrollBar
        Me.ColumnHeader1 = New System.Windows.Forms.ColumnHeader
        Me.ColumnHeader2 = New System.Windows.Forms.ColumnHeader
        Me.SuspendLayout()
        '
        'NotifyIcon1
        '
        Me.NotifyIcon1.ContextMenu = Me.ContextMenu1
        Me.NotifyIcon1.Icon = CType(resources.GetObject("NotifyIcon1.Icon"), System.Drawing.Icon)
        Me.NotifyIcon1.Text = "Notify"
        Me.NotifyIcon1.Visible = True
        '
        'ContextMenu1
        '
        Me.ContextMenu1.MenuItems.AddRange(New System.Windows.Forms.MenuItem() {Me.mnuShow, Me.mnuHide})
        '
        'mnuShow
        '
        Me.mnuShow.Index = 0
        Me.mnuShow.Text = "Show"
        '
        'mnuHide
        '
        Me.mnuHide.Index = 1
        Me.mnuHide.Text = "Hide"
        '
        'lvwLibrary2
        '
        Me.lvwLibrary2.Columns.AddRange(New System.Windows.Forms.ColumnHeader() {Me.ColumnHeader1, Me.ColumnHeader2})
        Me.lvwLibrary2.Location = New System.Drawing.Point(8, 8)
        Me.lvwLibrary2.Name = "lvwLibrary2"
        Me.lvwLibrary2.Size = New System.Drawing.Size(272, 216)
        Me.lvwLibrary2.TabIndex = 0
        Me.lvwLibrary2.View = System.Windows.Forms.View.Details
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(216, 248)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(64, 24)
        Me.Button1.TabIndex = 1
        Me.Button1.Text = "Button1"
        '
        'scrollV
        '
        Me.scrollV.Location = New System.Drawing.Point(280, 8)
        Me.scrollV.Name = "scrollV"
        Me.scrollV.Size = New System.Drawing.Size(16, 216)
        Me.scrollV.TabIndex = 2
        '
        'ColumnHeader1
        '
        Me.ColumnHeader1.Width = 94
        '
        'ColumnHeader2
        '
        Me.ColumnHeader2.Width = 109
        '
        'SystemTray
        '
        Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
        Me.ClientSize = New System.Drawing.Size(320, 273)
        Me.Controls.Add(Me.scrollV)
        Me.Controls.Add(Me.Button1)
        Me.Controls.Add(Me.lvwLibrary2)
        Me.Name = "SystemTray"
        Me.Text = "SystemTray"
        Me.ResumeLayout(False)

    End Sub

#End Region

    Public PreviousVItemCount As String
    Public TestArray(40) As ListViewItem
    Public FormLoaded As Boolean = False
    Dim OldValue As Integer = 0, ivlLodingList As Boolean = False

    Public Sub Populate()
        With lvwLibrary2
            Dim i As Integer
            Dim ColWidth As Integer
            Dim VitemCount As String

            For i = 0 To .Columns.Count - 1
                ColWidth += .Columns(i).Width
            Next

            If ColWidth > .Width Then
                VitemCount = (.Height - 39) / 14
            Else
                VitemCount = (.Height - 19) / 14
            End If

            If VitemCount.IndexOf(".") > 0 Then
                VitemCount = VitemCount.Substring(0, VitemCount.IndexOf("."))
            ElseIf VitemCount.IndexOf(".") = 0 Then
                VitemCount = 0
            End If


            If Not VitemCount = PreviousVItemCount Then
                scrollV.Maximum = TestArray.Length + 8

                If .Items.Count > 0 Then
                    .Items.Clear()
                End If

                For i = 0 To VitemCount - 1
                    Try
                        .Items.Add(TestArray(scrollV.Value + i))
                    Catch ex As Exception
                        MsgBox(ex.Message)
                    End Try
                Next
                PreviousVItemCount = VitemCount
            End If
        End With
    End Sub

    Public Sub Scroll()
        With lvwLibrary2
            If Me.lvwLibrary2.Items.Count > 0 Then
                If scrollV.Value < OldValue Then
                    .Items(.Items.Count - 1).Remove()
                    .Items.Insert(0, TestArray(scrollV.Value).Clone)
                ElseIf scrollV.Value > OldValue Then
                    .Items(0).Remove()
                    .Items.Add(TestArray(scrollV.Value).Clone)
                End If
                OldValue = scrollV.Value
            End If
        End With
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        ivlLodingList = True        'initialize a variable to true so that populate() will not get reloaded on loop
        Populate()       'this works fine, only crashes when it resizes
        ivlLodingList = False
    End Sub

    Private Sub scrollV_Scroll(ByVal sender As System.Object, ByVal e As System.Windows.Forms.ScrollEventArgs) Handles scrollV.Scroll
        Scroll()
    End Sub

    Private Sub lvwLibrary2_SizeChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles lvwLibrary2.SizeChanged
        If FormLoaded And ivlLodingList = False Then    'Check whether Populate() is running
            ivlLodingList = True    'initialize a variable to true so that populate() will not get reloaded on loop
            Populate()
            ivlLodingList = False
        End If
    End Sub

    Private Sub frmOptions_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim i As Integer
        For i = 0 To 40
            Dim item As New ListViewItem
            item.Text = "test - " & i
            item.SubItems.Add("test - " & i)
            TestArray(i) = item.Clone()
        Next
        FormLoaded = True
    End Sub
End Class

Bye
Ajai
0
 
LVL 2

Expert Comment

by:GohdanTheMoblin
ID: 12187350
OK, here's an example. I'm assuming your ListView has two columns.  You would define a structure like this:


      Public Structure DataItem
          Public item1 As String
          Public item2 As String
      
          Public Function ToListViewItem() As ListViewItem
              Dim lvi As New ListViewItem(item1)
              lvi.SubItems.Add(item2)
              Return lvi
          End Function
      End Structure
      
Now, you would have to modify TestArray to be an array of DataItem, and change your For loop like so:

        For i = 0 To 40
            Dim item As New DataItem
            item.item1 = "test - " & i
            item.item2 = "test - " & i
            TestArray(i) = item
        Next
       
When you want to add all items in the array to the ListView, you would simply do

      For Each item as DataItem in TestArray
            lvwLibrary2.Items.Add(item.ToListViewItem)
      Next
      
This seems roundabout, but it accomplishes a few things.  First, it stores your data in a format that is both easy for you to work with and easy to convert to the display format you want.  Second, since DataItem is separate from the ListViewItem, you can do whatever you want with the ListViewItem without having to worry about whether you are changing the array.
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Microsoft Reports are based on a report definition, which is an XML file that describes data and layout for the report, with a different extension. You can create a client-side report definition language (*.rdlc) file with Visual Studio, and build g…
Calculating holidays and working days is a function that is often needed yet it is not one found within the Framework. This article presents one approach to building a working-day calculator for use in .NET.
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

22 Experts available now in Live!

Get 1:1 Help Now