Link to home
Start Free TrialLog in
Avatar of CIW_George
CIW_GeorgeFlag for United States of America

asked on

Refer to Form by String (Visual Studio 2008)  Part 2

Thanks to everyone for their suggestions on how to refer to a form by using a string variable.  I now have the code working fine and is posted below.  The code in bold is the core code for the string variable usage, the rest of the code determines how many of the same MdiChild (frm_Junk in this case) are already open and passes this number to the next instance of the same MdiChild to be opened via a queue.

I am allowing the user to open multiple instances of frm_Junk because he/she can display different information in each instance and visually compare this information.

        Dim str_Form As String = "frm_Junk"
        Dim myForm As New Form
        myForm = CreateForm(str_Form)

        Cursor.Current = Cursors.WaitCursor

        '   Determine number of forms open.

        For Each obj_Form In Application.OpenForms
            If obj_Form.name.ToString.IndexOf(str_Form) >= 0 Then
                int_Count += 1
            End If
        Next

        '   Provide form offset pointer.

        If int_Count = 0 Then
            int_Forms = 0
        Else
            int_Forms += 1
        End If

        queue_Parameters.Clear()
        queue_Parameters.Enqueue(int_Forms)

        '   Open form.

        myForm.MdiParent = Me
        myForm.Show()

frm_Junk has the following code that positions the form within the MdiParent prior to the form actually being displayed.  I am doing this to display the form where I want it on the screen and prevent a brief display of the form in some arbitrary position.

Then problem I am having is frm_Junk opens as soon as encounter the myForm = CreateForm(str_Form) line in the calling program (above).  The result is the rest of the lines in the calling program arent processed, nothing is put in queue, and frm_Junk is opened as a regular form rather than a MdiChild.

Public Class frm_Junk

    Public Sub New()

        '   Position form prior to loading.

        InitializeComponent()

        'Dim f As Form = New Form()

        Dim int_Count As Integer = 0
        Dim int_Forms As Integer = queue_Parameters.Dequeue

        Dim int_Location_x As Integer
        Dim int_Location_y As Integer

        If int_Forms > 0 Then
            Me.Text += " [" & int_Forms & "]"
        End If

        SE_Common_Class.Get_Form_Size(Me.Width, _
                                      Me.Height, _
                                      int_Location_x, _
                                      int_Location_y, _
                                      Me.Name, _
                                      Me.WindowState)

        Me.Location = New Point(int_Location_x + (int_Mdi_x_Offset_Increment * int_Forms), _
                                int_Location_y + (int_Mdi_y_Offset_Increment * int_Forms))

        Me.StartPosition = FormStartPosition.Manual

    End Sub

    (more stuff)

End Class

QUESTION:  How can I refer to the form as a string (as Im doing in the calling program), yet still have the Public Sub New constructor in frm_Junk?  I really need to be able to position each instance of frm_Junk at a specific position on the MdiParent without the tacky looking screen flicker resulting from frm_Junk first opening and then getting repositioned?

Thank you in advance for your suggestions!
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

"Then problem I am having is frm_Junk opens as soon as encounter the myForm = CreateForm(str_Form) line in the calling program (above).  The result is the rest of the lines in the calling program arent processed, nothing is put in queue, and frm_Junk is opened as a regular form rather than a MdiChild."

To help you we'd really need to see what CreateForm() is doing!....  =)
Avatar of CIW_George

ASKER

My apologies!

    Public Shared Function CreateForm(ByVal formName As String) As Form
        ' Return the instance of the form by specifying its name.
        Return DirectCast(CreateObjectInstance(formName), Form)
    End Function
CreateObjectInstance() isn't a native method either....did it come from here?
http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/f140e00d-6eb8-4553-9ad7-153645de279e

Anyhoo, I don't see how that code is causing the form to be displayed.  Simply instantiating a form does not cause it to show.  Something else must be causing it to appear...

Also, in VB.Net 2008, you can get a count of the number of a particular type of form currently displayed like this:

        Dim JunkCount As Integer = Application.OpenForms.OfType(Of frm_Junk).Count
Sorry Idle_Mind, I need to proofread before I post!

You're correct about CreateObjectInstance:
-------------------------------
    Public Shared Function CreateObjectInstance(ByVal objectName As String) As Object

        Dim obj As Object

        Try
            If objectName.LastIndexOf(".") = -1 Then                'Appends the root namespace if not specified.
                objectName = [Assembly].GetEntryAssembly.GetName.Name & "." & objectName
            End If

            obj = [Assembly].GetEntryAssembly.CreateInstance(objectName)

        Catch ex As Exception
            obj = Nothing
        End Try

        Return obj

    End Function
-------------------------------------------
Thank you for your suggestion on counting open forms.

What else should I look for that might be causing the form to appear "prematurely"?  If it's not in the code in frm_Main that's calling frm_Junk, and it's not in the Public Sub New() section of frm_Junk, where else might it be?

George
I don't see anything obvious in your code that would cause the form to display prematurely.

Additionally, my own simple test did not reproduce the problem.

This leads me to believe the problem lies somewhere in code you have yet to show us...  =)
Imports System.Reflection
Public Class Form1

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim str_Form As String = "frm_Junk"
        Dim myForm As Form = CreateForm(str_Form)

        MessageBox.Show("Form created but not yet displayed?")

        myForm.MdiParent = Me
        myForm.Show()
    End Sub

    Public Shared Function CreateForm(ByVal formName As String) As Form
        ' Return the instance of the form by specifying its name.
        Return DirectCast(CreateObjectInstance(formName), Form)
    End Function

    Public Shared Function CreateObjectInstance(ByVal objectName As String) As Object
        Dim obj As Object = Nothing
        Try
            If objectName.LastIndexOf(".") = -1 Then                'Appends the root namespace if not specified.
                objectName = [Assembly].GetEntryAssembly.GetName.Name & "." & objectName
            End If
            obj = [Assembly].GetEntryAssembly.CreateInstance(objectName)
        Catch ex As Exception
        End Try
        Return obj
    End Function

End Class

Open in new window

Trust me Idle_Mind, I'm not trying to hide anything from you!  I appreciate your assistance and will be glad to provide whatever code you would like.

You've got the code I'm using in frm_Main to call frm_Junk, and the Public Sub New() in frm_Junk, where else do you suggest I look?

The sample code you've show above looks identical to what I'm using to open frm_Junk.

Do you also have Public Sub New() with InitializeComponent() in frm_Junk?

Why are your lines 16-22 (above) in green?  They don't appear to be commented out.  Just curious...

Thanks!
The coloring in the code above is done by EE not me...  ;)

I suggest you create a new, blank project with just Form1 and frm_Junk and the code I posted.  Let's see if the problem appears there too...
I shall.

Are you putting any code in frm_Junk?
No sir.  Start with a blank form...then start adding code to each part...slowly!...till you can reproduce the problem.  =)
Troubleshooting 101...

I've create a clean project with form1 and frm_Junk.  Form1 has a single button with your code.  frm_Junk has nothin'.  MsgBox displays.

Add my Public Sub New() in frm_Junk.  MsgBox never displayed.  Comment out all lines and MsgBox is displayed.  Uncomment one line at a time.

In Public Sub New(), replace:
    'Dim int_Forms As Integer = queue_Parameters.Dequeue'
with
    'Dim int_Forms As Integer = 0'
and MsgBox displayed.

So, what does 'queue_Parameters.Dequeue'  have to do with the price of tea in China?
Well, if you really started with a clean project then you'd have to add your queue_Parameters class to it.

Can you post the code for that class?
My apologizes, I tried to take a shortcut and may have gotten burned...

I did create the new project as I described.  After testing the basic configuration, I created Pbulic Sub New() in frm_Junk and added InitializeComponent() as the first line - the MsgBox was displayed.  I then took the shortcut and cut-and-pasted my full-blown Public Sub New() (as provided earlier in this topic), commented out all lines and proceeded to un-comment each line as described above.

The Dequeue line gave me an error, which it should have because queue_Parameters hadn't been defined in your code.  At the moment, I'm multi-tasking with a couple projects around the house, so I'm not running on all cylinders here.  I said "Ah-ha," it's the queue that's causing the problem without realizing it hadn't been defined.

So, I irrationally went back to my original program and commented out the 'Dim int_Forms as Integer = queue_Parameters.Dequeue' and replaced it with the 'Dim int_Forms as Integer = 1' line so the rest of the lines in Public Sub New() would execute.

When I set a break in frm_Main where I show frm_Junk (myForm.Show()), I break every time I have the Dequeue statement commented out in frm_Junk.  If I un-comment the Dequeue statement, I get an "InvalidOperation Exception - Queue empty" error and I never hit the breakpoint in frm_Main.

So, maybe I didn't burn myself?  I just wasn't clear as to all the steps I took to isolate the Dequeue line.

Am I still doing something wrong in trying to isolate the problem?  What else should I be looking at?
What is this line supposed to be doing?

    Dim int_Forms As Integer = queue_Parameters.Dequeue

Can you explain the logic and/or "flow" in plain english?
I'm using queue_Parameters to pass parameters between a calling form and the form being opened.  It is defined in a Module in frm_Main as 'Public queue_Parameters As New Queue(Of String)' and is global.  I've found it a convenient way to pass parameters.

In frm_Main (part of my initial post above), I'm using it to pass the number of forms open (now using your suggestion for counting forms):

        int_Forms = Application.OpenForms.OfType(Of frm_Construction_Methods).Count

        queue_Parameters.Clear()
        queue_Parameters.Enqueue(int_Forms)       ' Push int_Forms into the queue.

        '   Open form.

        myForm.MdiParent = Me
        myForm.Show()

In frm_Junk, I'm pulling int_Forms out of the queue (with 'Dim int_Forms As Integer = queue_Parameters.Dequeue') to "offset" each successive instance of frm_Junk (with 'Me.Location = New Point(....)') from the previous instance so they don't open on top of each other.

I happen to be using the variable name 'int_Forms' in frm_Main and frm_Junk for no particular reason - the are both locally defined in each form.

Am I making any sense?  Sometimes I miss describing something obvious, so please let me know.
This one has been sitting in the bottom of my Inbox for awhile...  =\

Where are you currently at?...have you progressed any further?
I changed my approach to addressing the original problem so I could keep the project moving.

However, I still see a number of applications that would benefit from being able to use your suggested approach to referring to a form using a string.  I believe the problem is my use of the Public Sub New with InitializeComponent().  As soon as I do the Dim myForm As Form = CreateForm(str_Form) line, VB decides to go ahead and open the new form, bypassing the MdiParent line. I need the Public Sub New to position the form before it opens - if I position the form in the Load section, the form opens in one location, then moves to the location I want it (leaving a brief flash in the original location).

I hope you were able to follow my description of queue_Parameters.

If you have any further thoughts on how to get around the InitializeComponent() issue, I would sincerely appreciate them.

Thank you again for your help!
I still don't see how InitializeComponent() or CreateForm() is causing the form to be displayed prematurely...  =\

In this example code, pressing the Button cause the form to be instantiated but NOT displayed.  Pressing the button a second time causes it to be displayed.

The problem is still somewhere else in your code!


Imports System.Reflection
Public Class Form1

    Private F1 As Form1 = Nothing

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        If IsNothing(F1) OrElse F1.IsDisposed Then
            Dim str_Form As String = "Form1"
            F1 = CreateForm(str_Form)
            MessageBox.Show("F1 created but not shown!")
        Else
            F1.Show()
            MessageBox.Show("F1 should be displayed now")
        End If
    End Sub

    Public Shared Function CreateForm(ByVal formName As String) As Form
        ' Return the instance of the form by specifying its name.
        Return DirectCast(CreateObjectInstance(formName), Form)
    End Function

    Public Shared Function CreateObjectInstance(ByVal objectName As String) As Object
        Dim obj As Object = Nothing
        Try
            If objectName.LastIndexOf(".") = -1 Then                'Appends the root namespace if not specified.
                objectName = [Assembly].GetEntryAssembly.GetName.Name & "." & objectName
            End If
            obj = [Assembly].GetEntryAssembly.CreateInstance(objectName)
        Catch ex As Exception
        End Try
        Return obj
    End Function

End Class

Open in new window

Try doing this with Form1 and see what happens.

My guess is you won't hit your message boxes in Button1_Click.  If you do get to a message box, than I haven't a clue what other code I have is causing the problem.  You've gotten cut-and-pastes of what I'm using.



 
Public Class Form1

    Public Sub New()

        InitializeComponent()

         Dim int_Count As Integer = 0

    end sub

end class

Open in new window

It behaves exactly the same...  =(

Here is the default constructor with the temp counter line:

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

        ' Add any initialization after the InitializeComponent() call.
        Dim int_Count As Integer = 0
    End Sub
OK, I think I see the difference between our two sets of code.

I copied everything you posted above (earlier this afternoon) into Form1 and added my Public Sub New into Form2.  I changed all Form1 references in your code to Form2.  Your code works exactly as advertised (including with the InitializeComponent())..

HOWEVER, I think where we're running into a problem is in your statement "Private F1 as Form2 = Nothing" (I changed Form1 to Form2).  It appears we're immediately defining F1 to be Form2 and it looks like we're creating a new instance (?) of Form2 in the "F1 = CreateForm("Form2")" statement.  The whole object of this exercise was to define a form with a string rather than pre-defining it with the desired form's name.

If you change "Private F1 as Form2 = Nothing" to "Dim F1 as Form = New Form", then the first time you click on the button, the "F1 should be displayed now." message is displayed and Form2 is opened.

What am I missing?
ASKER CERTIFIED SOLUTION
Avatar of Mike Tomlinson
Mike Tomlinson
Flag of United States of America image

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
Your change solved the problem.

I sincerely appreciate the time you've spent on this!

Thank you!
Excellent assistance (and very patient!).
Woohoo!...glad I "solved" the problem...  ;)

It's solved because YOU were able to take my boiled down code and apply it to the actual project.  =)

You'd be surprised how often that can't be done by the question askers...  =\