Referencing a form with a string value
Referencing a form with a string value
Referencing a form with a string value
Referencing a form with a string value
Referencing a form with a string value
Referencing a form with a string value Referencing a form with a string value Referencing a form with a string value Referencing a form with a string value Referencing a form with a string value Referencing a form with a string value Referencing a form with a string value Referencing a form with a string value
Referencing a form with a string value Referencing a form with a string value
Referencing a form with a string value
Go Back  Xtreme Visual Basic Talk > > > Referencing a form with a string value


Reply
 
Thread Tools Display Modes
  #1  
Old 08-30-2013, 08:38 AM
Snetzky Snetzky is offline
Freshman
 
Join Date: Dec 2009
Location: Iowa
Posts: 26
Default Referencing a form with a string value


I'm late to the vb.net game (migrating from a strong background in VBA) so bear with me.

I have an application where I hope to use xml defined menus to determine which form from which subproject gets displayed in a panel.

I'm assuming there is some way to reference a project and form without hardcoding the name but I haven't been able to figure out where that is.

In VBA, I can do a DoCmd.OpenForm and feed it the name of the form as a string.

Is there anything similar in VB.net? If so can you point me to some example code?
Reply With Quote
  #2  
Old 08-30-2013, 08:57 AM
DrPunk's Avatar
DrPunkReferencing a form with a string value DrPunk is offline
Senior Contributor

* Expert *
 
Join Date: Apr 2003
Location: Never where I want to be
Posts: 1,403
Default

Yeah, it's possible.

You use the string to get your form as a Type. Then you use Activator.CreateInstance to create that Type. If you know that type is going to be a form then you can cast it as a form and use it as one.

Note that you have to know the Namespace of your project. You can find this out from the project's property pages, under the Root Namespace field. It gets set to whatever you call your project unless you change it. In this example code it's left as [project namespace], but you'll have to change that to your project's namespace for the code to work. The full stop after the namespace is important so leave that.
Code:
Private Sub ShowFormByName(byval formName as string)

    dim t as Type = Type.GetType("[project namespace]." & formName)
    dim f as Form = CType(Activator.CreateInstance(t), Form)
   
    f.Show
End Sub
There should be lots more errorhandling going on in that code, but it demonstrates the principle.
__________________
There are no computers in heaven!
Reply With Quote
  #3  
Old 08-30-2013, 10:12 AM
Gruff's Avatar
GruffReferencing a form with a string value Gruff is offline
Bald Mountain Survivor

Retired Moderator
* Expert *
 
Join Date: Aug 2003
Location: Oregon, USA - deceased
Posts: 6,440
Default

To add to DrPunk's excellent post.

Under VB6 and VBA all forms defined were loaded when your project launched.
All forms defined at design-time were instantly available.

Under VB.NET forms are not special. They are classes just like everything else.
Say I had a custom message box form defined as "HintDialog" I created at design-time.

I can hard code, instantiate, and show the form (Dialog)

Code:
Public Class Form1 Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click Dim dlg As New HintDialog With dlg .lblHint.Text = "Hint: Do not shove lit candles up your nose!" If .ShowDialog = Windows.Forms.DialogResult.OK Then .LogHint() End If End With dlg.Dispose() End Sub End Class

This is pretty much how we create any object in VB.NET.

What DrPunk has shown you is a looser way to create any form (non-hard coded)

Pretty slick Doc.
__________________
Burn the land and boil the sea
You can't take the sky from me


~T

Last edited by Gruff; 08-31-2013 at 05:29 PM.
Reply With Quote
  #4  
Old 08-30-2013, 02:16 PM
Snetzky Snetzky is offline
Freshman
 
Join Date: Dec 2009
Location: Iowa
Posts: 26
Default Let me make sure I understand

Thanks for the more in depth explanation of the differences between VB6 and .net. That makes sense now.
Reply With Quote
  #5  
Old 09-03-2013, 02:58 PM
Snetzky Snetzky is offline
Freshman
 
Join Date: Dec 2009
Location: Iowa
Posts: 26
Default problem wtih declaring type

Code:
Private Sub ShowFormByName(byval formName as string)

    dim t as Type = Type.GetType("[project namespace]." & formName)
    dim f as Form = CType(Activator.CreateInstance(t), Form)
   
    f.Show
End Sub
There should be lots more errorhandling going on in that code, but it demonstrates the principle.[/QUOTE]

Tried your code and I can't get it to work. Here's what I wrote (taking off from what you gave me. I know there isn't any error handling, but I usually leave that until after I get the happy path to work)

Code:
Private Sub ShowFormInPanel(ByVal sProject As String, ByVal sForm As String)
        Dim sType As String = sProject & "." & sForm.Replace(" ", "")
        Dim t As Type = Type.GetType(sType)
        Dim frm As Form = CType(Activator.CreateInstance(t), Form)
        frm.TopLevel = False
        frm.Show()
        Me.pnlApplication.Visible = True
        Me.pnlApplication.Controls.Add(frm)
    End Sub
I'm passing the name of the project and the form in as sProject and sForm
I also import the subproject in the declarations of the form this code is part of.

The problem I'm running into, is that the line
Dim t as Type = Type.GetType(sType) never returns an object

So if I fill in the blanks:
Dim t as Type = Type.GetType("DataTools.CustomBump") it doesn't return an object that then can be instantiated in the next statement and things fail.

What am I doing wrong here?

Last edited by Snetzky; 09-03-2013 at 03:52 PM.
Reply With Quote
  #6  
Old 09-03-2013, 03:42 PM
AtmaWeapon's Avatar
AtmaWeaponReferencing a form with a string value AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

What specific failure do you get?

"It doesn't return an object" means you did not pass it the fully-qualified name of a type it can find.

"It doesn't return an object that can then be instantiated" means the object does not have a parameterless constructor.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #7  
Old 09-03-2013, 03:48 PM
Snetzky Snetzky is offline
Freshman
 
Join Date: Dec 2009
Location: Iowa
Posts: 26
Default

I'm still figuring out the ins and outs of exception handling in vb.net, but I suspect it's an issue with not fully qualifying the reference, since I was able to create a form in the main solution and reference it without any problems.

I have a refrence to the project in the Solution explorer and I have an Imports statement at the top of the form code. So if my project namespace is DataTools and my form name I'm referencing in there is CustomBump, I would assume that the reference would be DataTools.CustomBump

Intellisense appears to confirm this. However, when I try to run the code, t returns nothing as the result, in other words, it doesn't return an object.

To be more specific, it fails here:
Dim t As Type = Type.GetType(sType)
in that t never gets set to a type when I reference DataTools, but does if a reference a form that is part of the main solution project. Hope that helps.
Reply With Quote
  #8  
Old 09-03-2013, 10:07 PM
AtmaWeapon's Avatar
AtmaWeaponReferencing a form with a string value AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

I'd like to post a "round two" tomorrow with what I think is a better solution to this problem. Right now I'm on my way to bed so I'll tell you why I think this isn't working.

If you look at the documentation for Type.GetType(string), of interest is that you need an assembly-qualified name if the type is in a different assembly (mscorlib is an exception we'll ignore.)

So that means you need a name like "DataTools.CustomBump, YourAssemblyName, Version=1.0.0.0, Culture=neutral".

That looks like a pain in the butt, doesn't it? I can think of two ways I'd handle this.

Use More Reflection
The first is tried and true but a little hairy. You can take a shortcut to make it a lot easier, otherwise you're going to have to generate the assembly-qualified name regardless. (It's not really that bad to hide the ugliness in one spot, but I'll use what I call the "dummy type" approach.) This approach works best if you don't want to have to update the code every time you add a form.

The way it works is for you to load the assembly for reflection, then search it for the type name, then instantiate that type. Loading the assembly can be a little rough, so here's where a "dummy type" comes in. Pick some form you know is always in the assembly. In this example I'll use CustomBump. Since you've got a reference and an imports statement, something like this should work:
Code:
Function InstantiateForm(ByVal typeName As String) As Form
    ' Get the assembly (I can never remember if it's GetType() or TypeOf())
    Dim dummyType = GetType(DataTools.CustomBump)
    Dim theAssembly = dummyType.Assembly

    ' Search the assembly for the type
    Dim theType = theAssembly.GetType(typeName)

    ' Instantiate the type as a form
    Dim theObject = Activator.CreateInstance(theType)
    Return CType(theObject, Form)
End Function
That method still takes a "full class name", which is the namespace + class name. So you'd call it like:
Code:
Dim customBump As CustomBump = CType(InstantiateForm("DataTools.CustomBump"), DataTools.CustomBump)
It's a little work. The advantage is with a few tweaks you can use this approach to load types from assemblies you haven't referenced. Spiffy and versatile, and it's all hidden behind a method so you don't have to know how ugly it is.

The Factory Pattern
This technique is not so heavy on reflection, but requires you to update the method when you add new forms to the referenced DLL. It's the simplest possible thing:
Code:
Function InstantiateForm(ByVal typeName As String) As Form
    If typeName = "DataTools.CustomBump" Then
        Return New DataTools.CustomBump()
    Else If ...
        ...
End Function
It's lots of work, but the advantage here is you can decide things like "I don't want to use the namespace" or "I want to pick a different string token for the form". I tend to use this if there just won't be that many forms to work with.

I /think/ there's a third method involving generics that might be fun, but it's bedtime. Chew on these two.
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #9  
Old 09-04-2013, 05:05 AM
DrPunk's Avatar
DrPunkReferencing a form with a string value DrPunk is offline
Senior Contributor

* Expert *
 
Join Date: Apr 2003
Location: Never where I want to be
Posts: 1,403
Default

I don't want to confuse the issue here, I just want to point out that you can use an Object's GetType method to find out what it is you should be passing to the Type.GetType in order to create it.

For example, a new project with a Form1. If you wanted to know what you needed to pass to Type.GetType to create a Form1 you can do...
Code:
messagebox.show(me.GetType.ToString)
This will output 'WindowsApplication1.Form1' which tells you that's what you'd have to pass to Type.GetType in order to create a Form1 using that idea.

If you've got a class that you want to know about, just create it and output it's GetType.
Code:
Dim o as New CustomBump
messagebox.show(o.GetType.ToString)
__________________
There are no computers in heaven!
Reply With Quote
  #10  
Old 09-04-2013, 02:06 PM
Snetzky Snetzky is offline
Freshman
 
Join Date: Dec 2009
Location: Iowa
Posts: 26
Default I tried it and it doesn't work

The problem I'm having is that using the string I don't get anything returned. So if I used GetType(DataTools.CustomBump) I get a string back and can use that to retrieve a type, if I use
Type.GetType("DataTools.CustomBump") I get nothing.

I added an error handler to break and got the following error message:
Could not load type 'DataTools.CustomBump' from assembly 'WorkCenter, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null'.
Reply With Quote
  #11  
Old 09-04-2013, 02:27 PM
Snetzky Snetzky is offline
Freshman
 
Join Date: Dec 2009
Location: Iowa
Posts: 26
Default

Do I have to do something special to get the class library DataTools to be considered to be part of the main assembly?
Reply With Quote
  #12  
Old 09-04-2013, 04:13 PM
AtmaWeapon's Avatar
AtmaWeaponReferencing a form with a string value AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

Quote:
Originally Posted by Snetzky View Post
Do I have to do something special to get the class library DataTools to be considered to be part of the main assembly?
The only thing you can do to make that happen is to move the code into the same project. Have you tried my other suggestions?
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #13  
Old 09-06-2013, 09:16 AM
Snetzky Snetzky is offline
Freshman
 
Join Date: Dec 2009
Location: Iowa
Posts: 26
Default

I tried Atma's suggestions and they worked, but didn't get me away from having to hardcode the assemblies and forms somewhere. I was hoping the good doctor's solution would allow me to do what I want, but to no avail.

I think I'm probably working too hard to avoid using the extensibility capabilities in .net as they looked much more complicated than I wanted to get into, but it looks like they may be my only choice at this point if I don't want to hard code anything into the app, which I abhor.
Reply With Quote
  #14  
Old 09-06-2013, 09:41 AM
Snetzky Snetzky is offline
Freshman
 
Join Date: Dec 2009
Location: Iowa
Posts: 26
Default

Actually, I may have found a different solution, but I want to put it forth so you can warn me off if I'm going to get myself in trouble.

It looks like I can use the Assembly.Load method to load the assembly I want using the assembly name as a string, then reference the types within the assembly via string as well. That should give me what I need.

Thanks.
Reply With Quote
  #15  
Old 09-06-2013, 10:30 AM
Snetzky Snetzky is offline
Freshman
 
Join Date: Dec 2009
Location: Iowa
Posts: 26
Cool Reflections on Reflection

One of the reasons I like boards like this is that people use terms that you're not familiar with so you have to go look them up. So I went to read more about reflection and came up with the following:

Code:
Imports System.Reflection

Public Class fw_Application

    Private _LoadedAssembly As Assembly
    Private _CurrentForm As Form

    
    Public ReadOnly Property CurrentForm(ByVal sFormName As String) As Form
        Get
            Dim s As String
            s = GetType(DataTools.CustomBump).FullName
            _CurrentForm = _LoadedAssembly.CreateInstance(s)
            Return _CurrentForm
        End Get
    End Property

    Public Sub New(ByVal value As String)
        'Load Assembly 
        _LoadedAssembly = Assembly.Load(value)
    End Sub
End Class
I still need to add some finalize code to clean up any open objects when the user changes the current app, but it accomplishes what I want which is to allow me to load the form using just the name of the application and the form that I want.

I'm also thinking it might be useful to add a Changed form event so that I can perform internal navigation between the forms of the subapp. It would just pass a new form object to the primary panel display.

Last edited by Snetzky; 09-06-2013 at 10:37 AM.
Reply With Quote
  #16  
Old 09-06-2013, 11:05 AM
AtmaWeapon's Avatar
AtmaWeaponReferencing a form with a string value AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
 
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500
Default

Is it intentional that nothing in that code uses sFormName, and instead you always load the same form?
__________________
.NET Resources
My FAQ threads | Tutor's Corner | Code Library
I would bet money 2/3 of .NET questions are already answered in one of these three places.
Reply With Quote
  #17  
Old 09-06-2013, 11:11 AM
Snetzky Snetzky is offline
Freshman
 
Join Date: Dec 2009
Location: Iowa
Posts: 26
Default

Thanks..I missed that. I thought I had gone back and fixed that when I finalized things. Now I need to go back and look again.
Reply With Quote
  #18  
Old 09-06-2013, 11:44 AM
Snetzky Snetzky is offline
Freshman
 
Join Date: Dec 2009
Location: Iowa
Posts: 26
Default Okay..one more time!

This appears to work now: without having any hardcoded values

Code:
Imports System.Reflection

Public Class fw_Application
    Private _Name As String
    Private _LoadedAssembly As Assembly
    Private _FullName As String
    Private _CurrentForm As Object

    Public ReadOnly Property Name() As String
        Get
            Return _Name
        End Get
    End Property
    Public ReadOnly Property CurrentForm(ByVal sFormName As String) As Form
        Get
            Dim s As String

                 s = _Name & "." & sFormName

                 _CurrentForm = _LoadedAssembly.CreateInstance(s)
            Return _CurrentForm
        End Get
    End Property

    Public Sub New(ByVal sAssemblyName As String)
        'Load Assembly 
        _Name = sAssemblyName
        _LoadedAssembly = Assembly.Load(sAssemblyName)
        _FullName = _LoadedAssembly.FullName
    End Sub

    Protected Overrides Sub Finalize()
        If Not _LoadedAssembly Is Nothing Then
            _LoadedAssembly = Nothing
        End If
        If Not _CurrentForm Is Nothing Then
            _CurrentForm = Nothing
        End If
        MyBase.Finalize()
    End Sub
End Class
Reply With Quote
Reply


Currently Active Users Viewing This Thread: 1 (0 members and 1 guests)
 
Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off

Forum Jump

Advertisement:





Free Publications
The ASP.NET 2.0 Anthology
101 Essential Tips, Tricks & Hacks - Free 156 Page Preview. Learn the most practical features and best approaches for ASP.NET.
subscribe
Programmers Heaven C# School Book -Free 338 Page eBook
The Programmers Heaven C# School book covers the .NET framework and the C# language.
subscribe
Build Your Own ASP.NET 3.5 Web Site Using C# & VB, 3rd Edition - Free 219 Page Preview!
This comprehensive step-by-step guide will help get your database-driven ASP.NET web site up and running in no time..
subscribe
Referencing a form with a string value
Referencing a form with a string value
Referencing a form with a string value Referencing a form with a string value
Referencing a form with a string value
Referencing a form with a string value
Referencing a form with a string value Referencing a form with a string value Referencing a form with a string value Referencing a form with a string value Referencing a form with a string value Referencing a form with a string value Referencing a form with a string value
Referencing a form with a string value
Referencing a form with a string value
 
Referencing a form with a string value
Referencing a form with a string value
 
-->