Cannot access Disposed Object Error When Passing Controls To A New Form.

ALX

Well-known member
Joined
Nov 16, 2005
Messages
253
Location
Columbia, SC
Programming Experience
10+
I have recreated an error that I'm running into with this simple example. Clicking the "GO" button the first time generates an owned form that displays a few ListBoxes that were initalized in the parent form. Clicking the "GO" button a second time should dispose of the original owned form & create a new version of it. Instead it generates a runtime error:
"Cannot access a disposed object.
Object name: 'ListBox'."
I can step through the code where these ListBoxes are added to the owned form (both initially and the second time around), and the ListBoxes appear to be very much alive. It's when I call Form2.Show() the second time that the error occurs. Would any guru kindly enlighten a newbie here ???
Here is code for Form1:
VB.NET:
Public Class Form1
    Friend WithEvents Frm2 As Form
    Friend WithEvents ULB As New System.Windows.Forms.ListBox
    Friend WithEvents SLB As New System.Windows.Forms.ListBox
    Friend WithEvents XLB As New System.Windows.Forms.ListBox
    Dim Progress As Int16 = 0
 
    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Dim j As Int16
        For j = 1 To 10
            ULB.Items.Add(j.ToString)
            SLB.Items.Add(j + 20.ToString)
            XLB.Items.Add(j + 40.ToString)
        Next
    End Sub
 
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        If Progress = 0 Then
            NewInstance()
            Progress += 1
        Else
            CloseFrm2()
            NewInstance()
        End If
    End Sub
  
   Private Sub CloseFrm2()
        If Not Frm2 Is Nothing Then
            Frm2.Close()
            Frm2.Dispose()
            Application.DoEvents()
        End If
    End Sub
 
    Private Sub NewInstance()
        Frm2 = New Form2(ULB, SLB, XLB)
        Me.AddOwnedForm(Frm2)
        Frm2.Location = New Point(20, 20)
        Frm2.Show()
    End Sub
End Class
and here is code for Form2:
VB.NET:
Public Class Form2
    Friend Sub New(ByRef ULB As ListBox, ByRef SLB As ListBox, ByRef XLB As ListBox)
        InitializeComponent()
 
       Me.Controls.Add(ULB)
        ULB.Location = New Point(25, 35)
        ULB.Height = 100
        ULB.Width = 50
        ULB.Show()
 
        Me.Controls.Add(SLB)
        SLB.Location = New Point(100, 35)
        SLB.Height = 100
        SLB.Width = 50
        SLB.Show()
 
        Me.Controls.Add(XLB)
        XLB.Location = New Point(175, 35)
        XLB.Height = 100
        XLB.Width = 50
        XLB.Show()
    End Sub
End Class
 
Last edited:
Yes, and quite right that you should get that error, you are creating the list boxes inside form one and then passing them ByRef to form 2. Which means that you are holding an actual pointer to where those listboxes are stored in memory. So when you dispose if form2 it tries again to pass those listboxes to form 2 but of course it can't because they were disposed on when form 2 closed. You only created one instance on the listboxes so therefor you can only use them once. Corrections would be to create new instances of the listboxes when form 2 is instatiated.
 
vis781, doesn't that mean that passing the Listboxes ByVal instead of ByRef should work? I suspected it would, but the listboxes get disposed anyway.

Instead, like you also mentioned, (re)instantiating the Listboxes in NewInstance instead of Form1_Load does the trick indeed.

VB.NET:
Private Sub NewInstance()
    ULB = New System.Windows.Forms.ListBox
    SLB = New System.Windows.Forms.ListBox
    XLB = New System.Windows.Forms.ListBox
    Dim j As Int16
    For j = 1 To 10
       ULB.Items.Add(j.ToString)
       SLB.Items.Add(j + 20.ToString)
       XLB.Items.Add(j + 40.ToString)
     Next
     Frm2 = New Form2(ULB, SLB, XLB)
     Me.AddOwnedForm(Frm2)
     Frm2.Location = New Point(20, 20)
     Frm2.Show()
End Sub
 
You'd think so wouldn't you, but controls behave a bit strangly when passed byval. By defintion it should create a copy of the control and pass it to the second form but it doesn't. Controls that are passed byval behave as if they have been passed ByRef anyway. It's all because the base class control inherits from System.MarshallByRefObject. So basically if you are passing controls in most cases you may just as well pass then ByRef anyway.
 
In addition ALX i have changed the title of your post to something that better conveys your request. In the future could you please title you posts appropriately.
 
Yes, I will ...sorry about that.
I was aiming to have the listboxes in Form2 reflect changes that will be made to them in Form1. I 'm thinking that won't happen if they are just copies of the original listboxes. I will experiment with your suggestions.
Thanks for your help.
 
Last edited:
Well, I've found that removing the ListBoxes from Form2 (in Form2's closing event) does the job. 'Guess I thought that the ListBoxes would stay alive since they were still an active part of Form1. That's what I get for thinking! Thanks again !
 
I thought the code i posted (based on vis781's thoughts) already did exactly the same you wanted:

- You could still pass the controls byRef (they were not simple copies)
- You could control the listboxes from form1 (as long as form2 was open).

But i guess removing them from Form2 like you did is a neat trick i didn't expect to do the job :)

Greetz
 
Last edited:
Back
Top