Link to home
Start Free TrialLog in
Avatar of emub
emubFlag for United Kingdom of Great Britain and Northern Ireland

asked on

Removing form object from a 'collection' when closed

Hi,

Im having a little problem with forms :)

Basicly, I have a listview of records and when a user dbl click's a record it opens a new instance of the displayrecord form.  The user can open multiple records but if a use tries to open record for which they already have the form open it will just brings the existing open form to focus (I store he record ID in the .TAG so I know which form is for which record)

Now everything works great inc bring the already existing form to focus, apart from when I close a form it dosnt get removed from the collection object that stored all the forms so I cant reopen a record after its closed.

I've inc'd some code to hopfully make it clear how im doing it.

[Main Form (frmMain) With Listview on it]
Friend Shared oFormCollection as New Collection

[In Listview dblClick Code]
'// Before loading form lets make sure it isnt already open
Dim iRecordToOpen As Integer

iRecordToOpen = '// Code Here

Dim oForm As Form
Dim bLoadNewForm As Boolean = True

For Each oForm In frmMain.oFormCollection
      If oForm.Tag = iRecordToOpen Then
           oForm.BringToFront()
           oForm.Focus()
           bLoadNewForm = False
           Exit For
      End If
Next

'// If form isnt open then create a instance of the record form and display it
If bLoadNewForm Then
      Dim oNewForm As New frmDisplayRecord(iRecordToOpen)
      oNewForm.StartPosition = FormStartPosition.CenterScreen
      oNewForm.TopMost = True
      oNewForm.Focus()
      frmMain.oFormCollection.Add(oNewForm)
End If

[END]

It apears when I close the form, the instance of the form object stays in the oFormCollection, which mean if I wish to reopen the record it already thinks is open.  Am I going about this the wrong way?

Regards

=Daniel=
Avatar of RonaldBiemans
RonaldBiemans


change

If bLoadForm Then
      Dim oNewForm As New frmDisplayRecord(iRecordToOpen)
      oNewForm.StartPosition = FormStartPosition.CenterScreen
      oNewform.owner = me
      oNewForm.TopMost = True
      oNewForm.Focus()
      frmMain.oFormCollection.Add(oNewForm,oNewform.Name)
End If

in the closed event of your frmdisplayRecord add this

    Private Sub frmDisplayRecord_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed
        CType(Me.Owner, Form1).oform.Remove(Me.Name)
    End Sub

sorry this should be

 CType(Me.Owner, Frmmain).oform.Remove(Me.Name)
Djees, whats wrong with my typing

CType(Me.Owner, Frmmain).oFormCollection.Remove(Me.Name)

If I am understanding it all well:

you forgot to add this code

      bLoadNewForm = True

You should add this code inside the "Closing" (or something) event/handle of the opened Form. Thats why it thinks that its still open. So, as soon as that form is closed, its putting the boolean var bLoadNewForm back to value True.

Avatar of emub

ASKER

bLoadNewForm is Declared everytime the

"Private Sub listmenu_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.DoubleClick"

is called.
Avatar of emub

ASKER

Ok sorry, I forgot to add that  

Dim oNewForm As New frmDisplayRecord(iRecordToOpen)

frmDisplayRecord(ByVal RecordID As Integer) Is a function that reutrns a form from another DLL.  So effectivly the form DisplayRecord isnt in the same project

( Sorry I should have mentioned that )

So If couldnt put

    Private Sub frmDisplayRecord_Closed(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.Closed
        CType(Me.Owner, frmMain).oFormCollection.Remove(Me.Name)
    End Sub

As I would get the following message "Type 'frmMain' is not defined."


Ow, I understood that you have multiple forms open. Don't you need also multiple var bLoadNewForm. Like an array of bLoadNewForm(1 to Max Number of possible WindowWith_Record Open)?

Then you should get rid of this:


       bLoadNewForm is Declared everytime the

       "Private Sub listmenu_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.DoubleClick"

       is called.


And add
     
      bLoadNewForm(Form_Record_Open_ID) = True

       You should add this code inside the "Closing" (or something) event/handle of the opened Form. Thats why it thinks that its still open.
       So, as soon as that form is closed, its putting the boolean var bLoadNewForm back to value True.

For every possible open form!
if you reference that project in your dll you could
Avatar of emub

ASKER

Is there anyway to go though the forms objects in the collection and test if they have been closed or not?
Avatar of emub

ASKER

The frmMain is in the Main EXE,   frmDisplayRecord is in a seperate DLL, I presumed in the DLL you can only reference to other DLL not EXE's?
Okay,.. you need to find first out if this form is open (after the user clicked a record on the listview):

use this code:

dim boolean iRecordToOpen(iRecordToOpen)   'I assume this var has number 1 to 100 or so...


For Each oForm In frmMain.oFormCollection
      If oForm.Tag = iRecordToOpen Then
           oForm.BringToFront()
           oForm.Focus()
           bLoadNewForm = False
           Exit For
      End If
      '
      'If the user gets here, the form isn't open (yet)!
      'Set Boolean to True
     bLoadNewForm (iRecordToOpen) = True
Next


Now execute the following code:


If bLoadNewForm (iRecordToOpen) Then
      Dim oNewForm As New frmDisplayRecord(iRecordToOpen)
      oNewForm.StartPosition = FormStartPosition.CenterScreen
      oNewForm.TopMost = True
      oNewForm.Focus()
      frmMain.oFormCollection.Add(oNewForm)
End If


ASKER CERTIFIED SOLUTION
Avatar of RonaldBiemans
RonaldBiemans

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of emub

ASKER

:) I thinks there has been some crossed wires with the var bLoadNewForm, this was tempoary var I was using that was onyl referenced during the dbl_click process (my fault its was poorly written)

I restructurd the code to make it clear (even though the problem still exists) :) hehe

[on the main form]

Dim oFormCollection As New Collection     '// This hold a collection of all the forms that are open

[on the doubleclick part of the list view]

Private Sub listmenu_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.DoubleClick
      Dim iRecordToOpen As Integer
     
      iRecordToOpen =  '// Code to get ID of record from listviewitem

      If Not IsFormAlreadyOpen(iRecordToOpen) Then    'If the form isnt already open then open it and add it to the form collection
            Dim oNewForm As New frmDisplayRecord(iRecordToOpen)
            oNewForm.StartPosition = FormStartPosition.CenterScreen
            oNewForm.TopMost = True
            oNewForm.Focus()
            frmMain.oFormCollection.Add(oNewForm)
      End If
End Sub

[function within the listview]

Private Function IsFormAlreadyOpen(byVal RecordID As Integer) As Boolean
      Dim oForm As Form

      For Each oForm In frmMain.oFormCollection
            If oForm.Tag = RecordID Then
                 oForm.BringToFront()
                 oForm.Focus()
                 Return True
            End If
      Next

     '// If code should reach here then the record isnt already open
     Return False
End Function


[END]

Now when I close a record form, the instace of the object is still in the oFormCollection so when the function IsFormAlreadyOpen() is call it find the relevant form and tries to bring it to focus then returns True. How ever the user as already closed this form.
Sorry I posted my code not quite correct:

use these codes:

> Define this var 'global' (outside a sub):

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

dim boolean iRecordToOpen(iRecordToOpen)   'I assume this var has number 1 to 100 or so...

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

You need a boolean var for each possible form with record information.



> Put this piece of code in the Event thats called (OnDoubleClick?) of your ListView:

-----------------------------------------------------------------------------------------------------------------------------------------
'First we need to check if this form with clicked record is already open:

For Each oForm In frmMain.oFormCollection
      If oForm.Tag = iRecordToOpen Then
           oForm.BringToFront()
           oForm.Focus()
           bLoadNewForm = False
           Exit For
      End If
      '
      'If the user gets here, the form isn't open (yet)!
      'Set Boolean to True
     bLoadNewForm (iRecordToOpen) = True

Next

'If this Form is not found, the For-loop finish with the bLoadNewForm (iRecordToOpen)  set to  TRUE.
'If that is so, we have to generate the form and open it:

If bLoadNewForm (iRecordToOpen) Then
      Dim oNewForm As New frmDisplayRecord(iRecordToOpen)
      oNewForm.StartPosition = FormStartPosition.CenterScreen
      oNewForm.TopMost = True
      oNewForm.Focus()
      frmMain.oFormCollection.Add(oNewForm)
End If

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


Try it and maybe you like it!
Avatar of emub

ASKER

RonaldBiemans: I tried that but get the following error when trying to remove the "closed" form from the collection

"Additional information: Argument 'Key' is not a valid value."


 Daniellus83: With using an array, I would need to know how many record would be in the listview so I can declarer it? (I think)
Why not try to remove the form first?!

In the case the window is already open: the user wouldn't see it if it was already open:

Change this code:

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

Private Sub listmenu_DoubleClick(ByVal sender As Object, ByVal e As System.EventArgs) Handles MyBase.DoubleClick
      Dim iRecordToOpen As Integer
     
      iRecordToOpen =  '// Code to get ID of record from listviewitem

      If Not IsFormAlreadyOpen(iRecordToOpen) Then    'If the form isnt already open then open it and add it to the form collection

           'Try first to close the form: even when its not open:

             Try
                frmMain.oFormCollection.Remove( THE_FORM_iRecordToOpen)
             Catch EX As Exception
                'The code here would be called if the form couldn't be closed,.. just don't put here any code!
            End Try
     
            Dim oNewForm As New frmDisplayRecord(iRecordToOpen)
            oNewForm.StartPosition = FormStartPosition.CenterScreen
            oNewForm.TopMost = True
            oNewForm.Focus()
            frmMain.oFormCollection.Add(oNewForm)
      End If
End Sub

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

   
Avatar of emub

ASKER

RonaldBiemans:  

That idea seems to be along the right path, as the form object once its is closed still remains the the oFromCollection in a "disposed" state, hance its closed but its instance is still there in the collection.
Trying the .Select does cause an error

"System.ObjectDisposedException: Cannot access a disposed object named "UserDetails". Object name: "UserDetails"."

This is trapped, but the problem now lies with trying to find and remove that closed FORM from collection.
Avatar of emub

ASKER

Daniellus83: that would work but the problem im having is using the "frmMain.oFromCollection.Remove(key as string)" function.

I need to locate the correct form in the collection and remove it, but as far as im aware they are all called the same thing?
Avatar of emub

ASKER

ik this was fixed by


When adding an item to the collection I changed the code to

frmMain.oFormCollection.Add(oNewForm, RecordID)

and when removing the "closed" form I used

frmMain.oFormCollection.Remove(RecordID)



Avatar of emub

ASKER

Ok 1 last question regarding Exceptions

I tested this and I get the follow behaviour

Open Record Number 1, For shows
Close Record Number 1 form
Reopen Record Number 1,  there is a very long pause while its at the exception part, then form opens
Close Record Number 1 form
reopen Recrd Number 1, opens instantly

open and close and records repeatly and they open close without delay?

It would seem that when the program runs the first time it encounters the exception its does something (maybe searchs and loads somthing) then once its done it for the first time, after that its runs really smooth.
Yes,...

thats it!... I was just reproducing the problem with some buttons,.. it worked and mine is not neccesary any more.

:-\
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Anyway, I have one (hopefully good suggestion) since the try statement is not the finest to have...

> Why not keep a (global defined) array with opened ID wich are opened. Everytime one is closed, you search this array, if you find it, delete it in the Collection (and delete it in the array)

This way you have taken proper care of the window-management!
Avatar of emub

ASKER

hehe Wish it would "learn" alittle quicker :)
Avatar of emub

ASKER

An Array of all RecordID's open?