Call Sub or Function from another Open Form

Peter Allen
Peter Allen used Ask the Experts™
on
Experts,

I have a form with the following controls:
1. frmDataGridView_Designer           <-- Main Form
2. MenuStrip1                                    <-- Menu for Form
3. Panel_Menu                                    <-- Holds the ToolStrip (Buttons and Text)
4. ToolStrip_Project                            <-- ToolStrip holding buttons with Text/Graphics
5. Panel_Form                                    <-- Form showing the various Forms I use for
                                                                the Designer
6. Panel_Data                                      <-- Form showing results and Catalogs
7. StatusStrip1                                    <-- Shows current record status and Edit mode

Main form is called Designer. Panel_Form is called Editor and Panel_Data is called Catalog.  So each Panel listed above is opened properly and displays the desired controls as I want.  The nature of the UI I designed has the code for the Form in the Panel_Form and likewise for the Panel_Data form.  There is some duplication, but not much given this design.

When the Designer form opens it places two calls to the Panels to open as desired with the following code:
Editor Form
        Dim f_PanelForm As New frmDataGridViewProject_Editor(Me)
        f_PanelForm.TopLevel = False
        f_PanelForm.Parent = Me
        f_PanelForm.m_sFormFlagRecordEdit = "View"
        Panel_Form.Controls.Add(f_PanelForm)
        f_PanelForm.Show()

Open in new window


In the Editor Form I have the following:
Private frmDataGridView_Designer As frmDataGridViewProject_Designer

Open in new window


    Public Sub New(ByVal f_frmDataGridView_Designer As frmDataGridViewProject_Designer)

        Call InitializeComponent()
        frmDataGridView_Designer = f_frmDataGridView_Designer

    End Sub

Open in new window


Catalog Form
        Dim f_PanelData As New frmDataGridViewProject_Catalog(Me)
        f_PanelData.TopLevel = False
        f_PanelData.Parent = Me
        Panel_Data.Controls.Add(f_PanelData)
        f_PanelData.Show()

Open in new window


In the Catalog Form I have the following:
    Private frmDataGridView_Designer As frmDataGridViewProject_Designer

Open in new window


    Public Sub New(ByVal f_frmDataGridView_Designer As frmDataGridViewProject_Designer)

        Call InitializeComponent()
        frmDataGridView_Designer = f_frmDataGridView_Designer

    End Sub

Open in new window


Now with each form open I can make a call back to the Designer from each as I need to.  Can I add a Select Case to the "New" sub that will allow me to make a second call as needed so that I can call Shared or Public Catalog Subs and Functions from Editor and vice versa?
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Your question is:

    "Can I add a Select Case to the "New" sub that will allow me to make a second call as needed so that I can call Shared or Public Catalog Subs and Functions from Editor and vice versa?"

...but I'm not understanding exactly what that means.  You have the phrase "from Editor", which to me means you want to execute some code from within the context of the frmDataGridViewProject_Editor() form (which has a Reference to the main "Designer" form that was passed in via the Constructor).  What are you currently not able to do with that Reference that you want?
Most Valuable Expert 2012
Top Expert 2014

Commented:
> Can I add a Select Case to the "New" sub that will allow me to make a second call as needed so that I can call Shared or Public Catalog Subs and Functions from Editor and vice versa?

My understanding is that you want to call methods in catalog form from editor form and methods in editor form from catalog form when both forms have no link between them. Correct? One option is to declare both form variables at class level and as public so that each form can access the other form via the main form.
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Ah...after re-reading it, I think you are correct CodeCruiser!  =)
High School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009
Commented:
Here's a quick example of what CodeCruiser is suggesting...

In Designer, you'd declare two Public variables at the Form (Class) level to hold References to your Editor and Catalog Forms:
Public Class frmDataGridView_Designer

    Public f_PanelForm As frmDataGridViewProject_Editor = Nothing
    Public f_PanelData As frmDataGridViewProject_Catalog = Nothing

    ... other variables/subs/functions ...

End Class

Open in new window


Next, instead of using the local variable with "Dim" to create the Editor and Catalog forms, you just assign the instance to your previously declared variables above.

So this:

    Dim f_PanelForm As New frmDataGridViewProject_Editor(Me)

would become:

    Me.f_PanelForm = New frmDataGridViewProject_Editor(Me)



And, similarly, for the Catalog Form, this:

    Dim f_PanelData As New frmDataGridViewProject_Catalog(Me)

would become:

    Me.f_PanelData = New frmDataGridViewProject_Catalog(Me)



Now, from within the Catalog form, you can access Editor with:

    Me.frmDataGridView_Designer.f_PanelForm.XXX

And from within the Editor form, you can access Catalog with:

    Me.frmDataGridView_Designer.f_PanelData.YYY

If it's possible for one to be open while the other is closed, then you should check for Nothing before use:

    If Not IsNothing(Me.frmDataGridView_Designer.f_PanelForm) Then
        Me.frmDataGridView_Designer.f_PanelForm.XXX
    End If

*You would also need to set those references back to Nothing when those forms are closed.  This could be done by subscribing to the FormClosed() events of those forms and setting the appropriate reference to Nothing.
Peter AllenIT Specialist

Author

Commented:
Idle_Mind and CodeCruiser,

You were correct.  I do want to have references in both the Editor and Catalog to be able to access various Subs/Functions.  I was looking for articles that delbt directly with this issue, but didn't find any.  I was only able to piece together one reference issue and with further assistance from Idle_Mind was I able to create the constructor to pass the reference from the Designer to both of the other forms.  I realized later that I might need more.  And I wanted to be sure to get the coding correct.

The examples that you have given me are great.  I will try them in the AM.  Thank You.

OH, one other thing.  When I close the Editor form the Catalog Form closes as well.
Peter AllenIT Specialist

Author

Commented:
Idle_Mind,

I implimented the code changes and I can see the Public Variables and I do have access to the Public subroutines and functions as I wanted.  However, I am getting an error of "Object reference not set to an instance of the object".

The block of code that I get this error in is in the Editor (frmDataGridView_Editor):

        Call subFormStateInitialize()
        Call subFormStateControlsClear()
        Me.frmDataGridView_Designer.f_PanelData.subFormStateViewDataGridView(m_bUpdateFlagViewDataGridView)

Open in new window


The specific line that causes the error is:
        Me.frmDataGridView_Designer.f_PanelData.subFormStateViewDataGridView()

Open in new window


I was trying to figure out what exactly is causing the error on this line.  The Designer can be accessed as necessary and any Public subroutines or functions.  The Public variable can be accessed and the subroutine I am trying to execute is also Public.

This should work, but the error tells me I need to create a reference to the object.  How???
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
That should have been taken care of when you changed this line:

    Dim f_PanelData As New frmDataGridViewProject_Catalog(Me)

To:

    Me.f_PanelData = New frmDataGridViewProject_Catalog(Me)

This stores the instance of the Catalog form in the class level reference that is accessed from the other form.

*That same type of change needs to be made where both forms are created and displayed.
Peter AllenIT Specialist

Author

Commented:
Idle_Mind,

Yes I did that.  Just in case I did miss something I will attach the code for you to see.

First the code in frmDataGridView_Designer:

To define the Public variables:
    'Define Public variables for Editor/Catalog Form References
    Public f_PanelForm As frmDataGridViewProject_Editor = Nothing
    Public f_PanelData As frmDataGridViewProject_Catalog = Nothing

Open in new window


To open the Form Panel: frmDataGridView_Editor
    Private Sub subUpdateFormPanel()

        Me.f_PanelForm = New frmDataGridViewProject_Editor(Me)
        f_PanelForm.TopLevel = False
        f_PanelForm.Parent = Me
        f_PanelForm.m_sFormFlagRecordEdit = "View"
        Panel_Form.Controls.Add(f_PanelForm)
        f_PanelForm.Show()

    End Sub

Open in new window


To open the Data Panel: frmDataGridView_Catalog
    Private Sub subUpdateDataPanel()

        Me.f_PanelData = New frmDataGridViewProject_Catalog(Me)
        f_PanelData.TopLevel = False
        f_PanelData.Parent = Me
        Panel_Data.Controls.Add(f_PanelData)
        f_PanelData.Show()

    End Sub

Open in new window


When executed the Form and Panels are open.  The following code in both creates the Constructor that has the reference back to the Designer form:

In the Form Panel itself: frmDataGridView_Editor (Editor)
    'Define reference to Parent Form
    Private frmDGV_Designer As frmDataGridViewProject_Designer

Open in new window


    Public Sub New(ByVal f_frmDataGridView_Designer As frmDataGridViewProject_Designer)

        Call InitializeComponent()
        frmDGV_Designer = f_frmDataGridView_Designer

    End Sub

Open in new window


In the Data Panel itself: frmDataGridView_Catalog (Catalog)
    'Define reference to Parent Form
    Private frmDGV_Designer As frmDataGridViewProject_Designer

Open in new window


    Public Sub New(ByVal f_frmDataGridView_Designer As frmDataGridViewProject_Designer)

        Call InitializeComponent()
        frmDGV_Designer = f_frmDataGridView_Designer

    End Sub

Open in new window


Now that you see the code for referencing the Designer I know I can reference it from the Editor form with the following code and it works without an issue:
        Call frmDGV_Designer.subFormStateStatusBar(aStatusBarList)

Open in new window


The StatusBar on the Designer gets updated as I wanted it to.  I use 'Call' which is optional so the code reads clearly.

The error "Object reference not set to an instance of the object" still happens when I issue the call:
    Private Sub frmDataGridViewProject_Editor_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
            Handles Me.Load

        Call subFormStateInitialize()
        Call subFormStateControlsClear()
        Me.frmDGV_Designer.f_PanelData.subFormStateViewDataGridView()

Open in new window


in the line:
        Me.frmDGV_Designer.f_PanelData.subFormStateViewDataGridView()

Open in new window


From the Editor to bring up the DataGridView from the Catalog.  I am wondering if there is a way to directly call the Public sub on the Editor form from the Catalog form.  I know that the variables are Public, the Forms are Public so maybe somehow this call back to the Main Form and then the Editor form is getting things confused with the compiler???
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Hmmm...in your Constructors (the New() subs), try assigning the reference BEFORE InitializeComponent():
    Public Sub New(ByVal f_frmDataGridView_Designer As frmDataGridViewProject_Designer)
        frmDGV_Designer = f_frmDataGridView_Designer
        Call InitializeComponent()
    End Sub

Open in new window

Peter AllenIT Specialist

Author

Commented:
Idle_Mind,

No difference.  I changed the code in both the Editor and Catalog.  The forms can still get access to the Designer (Main form).

Would a Public Property help?
Is there a way to access the Editor directly from the Catalog?
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
No...this makes sense!  You can't create BOTH forms at the SAME TIME...

...so when you create the first Form, let's say it's Editor, it will hit the Load() event and attempt to access the Catalog form which has NOT been created yet.

This is why I said you should check for Nothing before accessing those References:
    If Not IsNothing(Me.frmDGV_Designer.f_PanelData) Then
        Me.frmDGV_Designer.f_PanelData.subFormStateViewDataGridView()
    End If

Open in new window

Peter AllenIT Specialist

Author

Commented:
Idle_Mind,

Could I create a class that would hold references to open forms?  This way I could reference the class in the Editor and Catalog forms and just make one call to the Public sub with class reference instead of how I would do it now which is to first reference the Designer and then the desired public property and then the Public sub?
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
You could...but it wouldn't matter.  The root problem is that the Load() event fires directly after the Constructor is called (in response to instantiating the class with "New").  So as soon as you create the first form it is attempting to access the other one (which hasn't been created yet).

Your solution is to pick one of these:
(1) Don't access the other form from the Load() event
(2) Wrap that call in the IsNothing() check as demonstrated
Peter AllenIT Specialist

Author

Commented:
Idle_Mind,

In that case should I place the code to update the DataGridView after the Catalog form is loaded?  Still including the check for is nothing.

I should have realized this before.  It makes perfect sense.  I was trying to call a sub on a form that wasn't loaded yet.
Peter AllenIT Specialist

Author

Commented:
THANK YOU.  You've been a BIG help Idle_Mind.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial