1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

VB.Net Finding open forms, and allowing only a single instance of each

Discussion in 'Scripting & Programming' started by Fergal1982, Dec 20, 2007.

  1. Fergal1982

    Fergal1982 Petabyte Poster

    4,196
    171
    211
    I've been invovled in a discussion over at vbcity regarding how to check for an existing instance of an open form.

    Currently at work, we have two variables for each form - myformisopen, and myform. when the form opens, it sets myformisopen to true, and is instantiated against the public variable myform.

    When we want to check, we check against myformisopen.

    However, I've been looking into better methods to do this. And wanted to know what other developers thought was better. I came up with three methods:

    1: Use the method as above (or just use a myform variable, and check if it exists or isnt disposed)

    2: Loop through the forms in my.application.openforms to check for the form in question.

    3: Insantiate a single hashtable and store a reference to the forms in this. I can add code to the forms to add and remove themselves from the table as they are opened. Then I can check against the hashtable to see if one exists.

    I used the following analogy to explain my thinking:

    Imagine all the mailboxes in a street. Periodically, I want to know a specific mailbox contains a package, but the specific box changes each time.

    Option 1: I run down the road, until i get to the box and look inside (iterating through open forms). This takes time and, every time I need to check again, I have to spend all that time again. As more houses are added, I need (potentially) to travel further each time.

    Option 2: I fit each box with a red plastic flag. When a package is delivered, the flag is raised (using a defined variable for each form). This is quicker (I can just use my telescope to check it out), but means that I would have to remember to fit the flag to each box as its added to the street.

    Option 3: I have a whiteboard on my wall. When a package is delivered, I write the house number on the board (Using a hashtable). This is even quicker. it requires a little bit of overhead every time a package is delivered, but i can tell at a glance if number 14 has a package. And it doesnt matter if new houses are added to the street, i just add them to the board as and when required. If the package is removed from the box, I simply wipe the number from the board, and i can use that space for another house as needed.

    In my rationalisation, Option three had the least 'Active Overhead' (I think of Active Overhead as the time the app spends doing something, Passive Overhead is the memory is consumes whilst running. Real terms? I suspect not, but my phrases any way).

    I decided to test Options 2 and 3 against each other (Option 1 would be difficult to test in the manner i was using). So I created an app, and added two forms to it. Form1 was given two buttons, and two labels. The code for both forms is:

    Code:
    Public Class Form1 
    
        Public hsh As New Hashtable 
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load 
            For i As Integer = 1 To 100 
                Dim frm As New Form2(i) 
                frm.ShowInTaskbar = False 
                frm.Show() 
            Next 
        End Sub 
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click 
            Dim sw As New Stopwatch 
            sw.Start() 
            For i As Integer = 0 To (My.Application.OpenForms.Count - 1) 
                If My.Application.OpenForms.Item(i).Text = "90" Then 
                    Dim frm As Form2 = My.Application.OpenForms.Item(i) 
                    Label1.Text = sw.ElapsedMilliseconds.ToString 
                End If 
            Next 
            sw.Stop() 
        End Sub 
    
        Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click 
            Dim sw As New Stopwatch 
            sw.Start() 
            If hsh.Contains("90") Then 
                Dim frm As Form2 = hsh.Item("490") 
                Label2.Text = sw.ElapsedMilliseconds.ToString 
            End If 
            sw.Stop() 
        End Sub 
    End Class 
    
    Public Class Form2 
        Private _i As Integer 
    
        Private Sub Form2_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load 
            Form1.hsh.Add(_i.ToString, Me) 
            Me.Text = _i 
        End Sub 
    
        Public Sub New(ByVal i As Integer) 
    
            ' This call is required by the Windows Form Designer. 
            InitializeComponent() 
    
            ' Add any initialization after the InitializeComponent() call. 
            _i = i 
    
        End Sub 
    End Class
    
    To be fair in the test, I chose to take a reference to the form on finding it, since this was the point of the function

    Running this, looping through the openforms returns 6 milliseconds, whereas the hashtable returns 0.

    Scaling it up to 500 (ok, Im never going to need to do this, but its a concept test, rather than a practical need), and checking for form 490, returns the looping at around 35-40, although sometimes going as high as 100. The hashtable still returned 0.

    Admittedly this is in milliseconds, so the noticeable time is negligable, as Laura pointed out, but its interesting to see the difference in performance.



    I've been a little lazy in posting this, copying much of what I said direct from my post at VBCity.

    Thought I'd repost this here, since it might be of interest to some of you.
     
    Certifications: ITIL Foundation; MCTS: Visual Studio Team Foundation Server 2010, Administration
    WIP: None at present
  2. ThomasMc

    ThomasMc Gigabyte Poster

    1,507
    49
    111
    Pritty sweet, thanks for that Fergal as its something that will come in very handy with a project i got on the go right now, BTW my results where between 4/5 ms and 0

    Rep added, very informative and examples to back it up
     
    Certifications: MCDST|FtOCC
    WIP: MCSA(70-270|70-290|70-291)
  3. Fergal1982

    Fergal1982 Petabyte Poster

    4,196
    171
    211
    Thanks, its been pointed out that for an accurate test, I should really be using the middle form. I disagree slightly, but agree that simply checking for the end forms causes a bias against a normal distribution. To be fully fair and accurate, I should really be testing the time it takes to search for 5 or so forms, whose numbers are generated randomly. This would be more fair.

    However, in this instance, I wanted to know the maximum time it might take to find a form - in other words how long a form might hang for, whenever you wanted to check for a form and get its reference if it exists: I wanted to know the worst case scenario.

    Thomas, let me know if you want to know how to use the hashtable to work with singleton forms. I have code to do it already, so its easy enough to show you how to do it. Although Im sure you can work it out from the examples I give.
     
    Certifications: ITIL Foundation; MCTS: Visual Studio Team Foundation Server 2010, Administration
    WIP: None at present
  4. netherstar

    netherstar New Member

    2
    0
    1
    Let me see if I got this right, in psuodocode at least.

    Public Class Form1
    ___Public hsh as New Hashtable
    ___Private Sub btnLoadForm2_Click(byVal sender and e...)
    ______Dim f As Form2
    ______If hsh.Contains("Form2") Then
    _________f = hsh.Item("Form2")
    ______Else
    _________f = New Form2
    ______End If
    ______f.Show()
    ______f.Focus()
    ___End Sub
    End Class

    Public Class Form2
    ___Private Sub Form2_Load(ByVal sender and e...)
    ______Form1.hsh.Add("Form2", Me)
    ___End Sub

    ___Private Sub Form2_FormClosing(ByVal sender and e...)
    ______Form1.hsh.Remove("Form2")
    ___End Sub
    End Class

    This is pretty cool. Last month I'd been trying to work this problem, the long way around.
    (I tried that indent tool, and didn't like it. How do you guys get it to look right?)

    Dave
     
  5. Fergal1982

    Fergal1982 Petabyte Poster

    4,196
    171
    211
    You seem to have the gist of how to use the Hashtable.

    Which indent tool are you referring to? If you mean, how did I get the code formatted with the correct indents, then I simply wrote the code in visual studio (which applied the indents automatically), and then copied it into the post. If you use the [ code ] tags (without the spaces between the brackets and 'code'), CF will maintain the formatting.

    Edit:
    I just noticed that my analogies are a little mixed up. For clarity, this is how they match the Methods:

    1. IsOpenVariable: Option 2
    2. Application.OpenForms: Option 1
    3. Hashtable: Option 3
     
    Certifications: ITIL Foundation; MCTS: Visual Studio Team Foundation Server 2010, Administration
    WIP: None at present
  6. netherstar

    netherstar New Member

    2
    0
    1
    As I am saving items to the hashtable,

    "Form1.hsh.Add("Form2", Me)

    Am I saving a reference to the form or am I copying (duplicating) the entire form into the hashtable?
    The latter seems like it could be a memory hog.

    Dave
     
  7. Fergal1982

    Fergal1982 Petabyte Poster

    4,196
    171
    211
    No, its only copying the reference to the form. Remember, when you copy a reference type, you copy the reference to the memory location, not the object itself.
     
    Certifications: ITIL Foundation; MCTS: Visual Studio Team Foundation Server 2010, Administration
    WIP: None at present
  8. volatile

    volatile Nibble Poster

    60
    3
    19
    Maybe I'm reading it wrong but in your topic it says only a single instance of each. Don't you mean a single of each type of form? Your current code does no type checking to see what kind of form it actually is. All it does is assume that it's base class is of type System.Windows.Forms and checks the Text value of form. So there can be multiple instances of Form2 as long as the text value is different. Did I read this wrong? Not too terribly familiar with VB but in C# you could do something like the following for type checking:

    foreach (window in this.Windows)
    {
    // Or use a hash table
    if (window is a Form2)
    {
    // Do this....
    }
    }

    I'm also a little bit confused as to why you wouldn't want a handle on the forms in the first place. Once instantiated are the forms not needed again and can process independently of the application? Also, if you are only looking to hold only once instance and not prevent other instances of the same type of form I'd worry about making your application threadsafe. Again, sorry if I totally misunderstood your post.
     
    Certifications: Computer Science Degree, A+
  9. Fergal1982

    Fergal1982 Petabyte Poster

    4,196
    171
    211
    You could use a method similar to what you describe, sure. My code uses text, simply because at the time, the forms were title specific. I was creating conversation windows, and the title reflected who the conversation was with. In the event of a new message, it checked the available forms, and either created a new form, or passed the message onto an existing form for that person. Thus, from my motivation, the table only actually contained one type of form, but multiple instances of them.

    How you adapt the code to fit individual requirements is, of course, entirely up to each person and their implementations. You can restrict it to single instances of a type of form, or a single type, with multiple instances.

    Also, the whole point of my post is to not use the this.windows or my.application.openforms, since it means iterating through every item in the list until you find the one you are looking at (if at all).

    The application may have further modification requirements in order to make it threadsafe, depending on how/what it does in those forms, but again, thats in individual application requirement. In one of the applications I was writing in that I intended to use this code, the block of calling code would get the reference to the specific form, and call a function within it. That function would do anything necessary with the existing data on the form, then blow it all away and replace it with the new data. Since it was all on the main thread, there was no issue. On other applications, there may be.

    The point of my post wasnt to give you all the answers, merely to provide a methodology that could be used to fulfil your needs. Its up to you to make adaptions and allowances to fit your application model.
     
    Certifications: ITIL Foundation; MCTS: Visual Studio Team Foundation Server 2010, Administration
    WIP: None at present
  10. volatile

    volatile Nibble Poster

    60
    3
    19
    Whoops, my fault for misreading your post. If you put it that way and the forms were supposed to behave kind of like instant message windows, then I see what you were doing. Sorry, I'll just move along.
     
    Certifications: Computer Science Degree, A+
  11. Fergal1982

    Fergal1982 Petabyte Poster

    4,196
    171
    211
    Thats correct. At the time thats exactly what I was writing.

    It's worth pointing out (for those who don't know my backstory) that I've only been a full time developer for just over a year now. And before that, I only had a year or so part time development experience (most of it in vbscript I might add). Prior to this, I didnt have so much as a standard grade in Computing. So when I wrote the above post, I had only been developing for around 6 months. Its entirely possible that there are errors in it, or ways to modify it to work better.

    I partly posted it here to show others what I had devised, but also to encourage discussion on it. I hadn't thought to include checks on the form type, rather than name - simply because it wasnt part of my requirements.
     
    Certifications: ITIL Foundation; MCTS: Visual Studio Team Foundation Server 2010, Administration
    WIP: None at present

Share This Page

Loading...