Solved

Reference to a Form stored in a Public Property

Posted on 2012-04-11
11
223 Views
Last Modified: 2012-04-16
Experts,

I have a Main form called Designer.  The Designer has a StatusBar.  The Designer also has two panels (Panel1 and Panel2).  Each Panel has a Form to show.  I have decided that there is no need to have multiple StatusBars, only the one on the Designer.

On the Form opened in Panel1 I store the StatusBar values in an ArrayList.  I want to pass this ArrayList to the Parent Designer Form Public Sub that updates the StatusBar.

So to update the StatusBar on the Designer I need a reference to the Designer form.  Could I use a Public Property defined as Object or Variant?  Would/Could I assign the value of the Public Property just after I create it?

Example:

Dim frm as new FormA
frm.p_FormInstance = frm

Then I could do something like:
call p_FormInstance.subUpdateStatusBar(aList)

aList is the list of two settings for the StatusBar to update.
0
Comment
Question by:Peter Allen
  • 4
  • 3
  • 2
  • +2
11 Comments
 
LVL 15

Expert Comment

by:David L. Hansen
ID: 37834562
Take a look at "my.forms...." you can usually reference your forms directly using that.
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 37835182
Is "Designer" the MAIN form that the application STARTS with?  Is it also the value set as the "Startup Object" in Project --> Properties?

If yes to both, then you can simply reference the Designer "BY NAME" as the default instance is what is displayed.

So, from within FormA, you can simply do:

    Designer.subUpdateStatusBar(aList)
0
 
LVL 35

Assisted Solution

by:Miguel Oz
Miguel Oz earned 25 total points
ID: 37835184
You need to cast p_FormInstance to your class type (FormA) using CType or DirectCast and then access the required method. Check:
http://www.codeproject.com/Articles/5044/Cheat-Sheet-Casting-in-VB-NET-and-C

For example: Replace p_FormInstance.subUpdateStatusBar(aList) with:

' Cast to Form1
Dim cast_Form As FormA = CType(p_FormInstance, FormA)
'  then you can call method
cast_Form.subUpdateStatusBar(aList)
0
 
LVL 40

Assisted Solution

by:Jacques Bourgeois (James Burger)
Jacques Bourgeois (James Burger) earned 250 total points
ID: 37836516
Unless you have many calls to make to the designer, do not create variable when you have only one call to make. The system needs to work in order to create a variable and destroy it afterward.

Go directly to the Designer from with code like the following:

DirectCast(Me.Parent.Parent, Designer).subUpdateStatusBar(aList)

Me is the Form inside the Panel
Me.Parent is the Panel
Me.Parent.Parent is the Parent of the Panel, that is your Designer

Note that I use DirectCast instead of CType. CType is not a cast, it is a type conversion. It works but requires more overhead than DirectCast that simply works directly with the pointer to the form.
0
 

Author Comment

by:Peter Allen
ID: 37837079
JamesBurger,

Using DirectCast with your example worked like a charm.  I have one question though...

I have the following code:

Private Sub subUpdateFormPanel()

        Dim f_PanelForm As New frmDataGridViewProject_Editor
        f_PanelForm.TopLevel = False
        f_PanelForm.Parent = Me
        f_PanelForm.p_sFormRecordEditState = "View"
        f_PanelForm.p_fParentForm = Me.ParentForm
        Panel_Form.Controls.Add(f_PanelForm)
        f_PanelForm.Show()

    End Sub

Which defines the Form I am opening in the Panel.  The Editor form calls the StatusBar Subroutine to update the StatusBar on the Designer Main Form (which is not the MIDI container, but just another form in the application):

        Call DirectCast(Me.Parent.Parent.Parent.Parent, frmDataGridViewProject_Designer).subUpdateFormStatusBar(aStatusBarList)

Worked, but if I want to refer to more subroutines on the Designer form should I store this reference in one variable as the form is opened?  Once the form closes the variable goes away.

So I thought I could do something like:

Dim objName as new Object
objName = Me.Parent.Parent.Parent.Parent
0
IT, Stop Being Called Into Every Meeting

Highfive is so simple that setting up every meeting room takes just minutes and every employee will be able to start or join a call from any room with ease. Never be called into a meeting just to get it started again. This is how video conferencing should work!

 
LVL 85

Expert Comment

by:Mike Tomlinson
ID: 37837289
Did my comments not apply to your situation?...
0
 
LVL 40

Accepted Solution

by:
Jacques Bourgeois (James Burger) earned 250 total points
ID: 37838371
@Idle_Mind

Your comment is not a very good way to work, even it if applies. It assumes that the form will always be the main form or the startup form. If for some reasons in the future (and these things happen during the life of an application) Peter finds out that he needs to start in another form or start in a Main method in order to initialize a few things at the start of the application or to trap errors globally, it will stop working. The DirectCast approach will work in all situations.

I always think with maintenance in mind when I code.

------

@Peter_Allen

Do not call New on a variable when you assign it an already existing object. New create an object in memory. In your 2 lines, you first create an object (job for the system) and then the line right after you assign another object to the variable, so the system has to destroy the object that you have just created and never used. You use New only when you need to create a brand new object.

And try as much as possible not to us late binding (variables of type Object). It is a pain to use (you need to cast all the time), you do not have IntelliSense, the compiler is not able to detect errors and they have an impact on performance because the checks usually done by the compiler need to be done at runtime. Be specific when you know the type of an object.

And in .NET, when you already have the object at the point of declaration, you can do the assignment on the same line as the declaration.

I would rather go for something such as the following:
Dim designerForm as frmDataGridViewProject_Designer = DirectCast(Me.Parent.Parent.Parent.Parent, frmDataGridViewProject_Designer)

Open in new window

Another approach would be to add a constructor to you panel form and pass the designer to that constructor:
Private designerFormDesigner As frmDataGridViewProject_Designer
Public Sub New(designer As frmDataGridViewProject_Designer )
    InitializeComponent()
    designerForm = designer
End Sub

Open in new window

When you create the panel form, initialize this way (I understand that you instantiate it in the Panel):
Dim f_PanelForm As New frmDataGridViewProject_Editor(DirectCast(Me.ParentForm,frmDataGridViewProject_Designer)

Open in new window


From then on, no matter which of the 2 techniques you use, when you need to call a method on the designer form:
designerForm.subUpdateFormStatusBar(aStatusBarList)
designerForm.AnotherMethod
x=designerForm.SomeFunction
MessageBox.Show(designerForm.DisplayMessage)

Open in new window

Not seeing all your code, I might have used the wrong identifiers of variables in some places, so you might have to change a name here and there.
0
 
LVL 85

Assisted Solution

by:Mike Tomlinson
Mike Tomlinson earned 225 total points
ID: 37838668
"I always think with maintenance in mind when I code."

Haha!...you sir are kidding right?  How can you make that statement and then a couple lines later recommend using "Me.Parent.Parent.Parent.Parent"?!

That suffers the exact same problem that you cited for my suggestion:

    "If for some reasons in the future (and these things happen during the life of an application) Peter finds out that he needs to start in another form or start in a Main method in order to initialize a few things at the start of the application or to trap errors globally, it will stop working."

If the container hierarchy changes then you have to figure out another mess to place in there instead.

Instead of using a TIGHTLY COUPLED solution (which passes specific types of references), I'd recommend a LOOSELY COUPLED approach.  Make your "embedded form" RAISE A CUSTOM EVENT that passes out the ArrayList.  The Designer form will Subscribe to that custom event at the embedded forms creation time.  Now, whenever that event is received, the Designer form can call whatever method it wants directly.  References don't need to be passed and it doesn't matter if the start form or container hierarchy changes.
0
 
LVL 40

Assisted Solution

by:Jacques Bourgeois (James Burger)
Jacques Bourgeois (James Burger) earned 250 total points
ID: 37838845
@Idle_Mind

It was not "a couple lines later", but a couple lines earlier. And that makes a difference. As a trainer, I always try to adapt my answers to the level of the student who asks the question. The best answer is not always the best one to give. If the student is not to the level to understand the best solution, give him a solution he can understand. Later on, as he evolves as a programmer, you will teach him better ways to do things.

I do the same here on the Exchange.

Not knowing Peter's level through the simple code in his question, I went first for the simplest solution.

Then I answered to you, knowing that you are not a beginner.

And seeing that Peter was a little more advanced than what showed up in his first post and having got precisions on his needs, I went with a more advanced answer and a better solution.
0
 
LVL 85

Assisted Solution

by:Mike Tomlinson
Mike Tomlinson earned 225 total points
ID: 37838987
Fair enough...

Here's a simplified example of how the custom event can be implemented:
Public Class Form1

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Dim f2 As New Form2
        AddHandler f2.Status, AddressOf f2_Status
        f2.TopLevel = False
        f2.FormBorderStyle = Windows.Forms.FormBorderStyle.None
        f2.Dock = DockStyle.Fill
        Panel1.Controls.Add(f2)
        f2.Show()
    End Sub

    Private Sub f2_Status(values() As String)
        If values.Length >= 3 Then
            ToolStripStatusLabel1.Text = values(0)
            ToolStripStatusLabel2.Text = values(1)
            ToolStripStatusLabel3.Text = values(2)
        End If
    End Sub

End Class

Public Class Form2

    Public Event Status(ByVal values() As String)

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
        RaiseEvent Status(New String() {"cat", "dog", "fish"})
    End Sub

End Class

Open in new window


*Note that the custom event can pass out any type(s) that you choose, and that you can use RaiseEvent in response to code instead of user interaction.
0
 

Author Closing Comment

by:Peter Allen
ID: 37851080
The feedback is Great.  Thank you everyone.
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Article by: Kraeven
Introduction Remote Share is a simple remote sharing tool, enabling you to see, add and remove remote or local shares. The application is written in VB.NET targeting the .NET framework 2.0. The source code and the compiled programs have been in…
The ECB site provides FX rates for major currencies since its inception in 1999 in the form of an XML feed. The files have the following format (reducted for brevity) (CODE) There are three files available HERE (http://www.ecb.europa.eu/stats/exch…
This video discusses moving either the default database or any database to a new volume.
This tutorial demonstrates a quick way of adding group price to multiple Magento products.

757 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

16 Experts available now in Live!

Get 1:1 Help Now