Jim Duffy, Visual Basic MVP, TakeNote Technologies
This article is focused on answeringa simple yet not-so-easy to answer question. “How do instantiate an object whenthe class I want to instantiate is determined at runtime, not compile time?” Ifyou’re wondering why you would want to do that in the first place, this articleprovides a real world reason why as well.
A project I have been assisting aclient’s development team on required a list of canned reports be available forthe user to select from. A report selection form (frmReportListing) has a listbox containing all the reports is displayed when the user selects “Reports”from the application toolbar. The list box is populated from records in aReports table where each record contains information about a specific report.So far so good.
Continuing, each report has its ownfiltering criteria, selecting a beginning & ending date for one report andmaybe selecting a specific product category for inventory analysis for another.In order to provide the user with the ability to specify the reportingfiltering criteria, each report has a filtering criteria form that provides theuser the ability to filter the data in the report. Again, so far so good.
Where things begin to getinteresting is that the structure of the Reports table looks like this:
ReportID
Title (displayed to the user in thereport selection form list box)
FormName (name of the selectioncriteria form to display when the report is selected)
The issue that needed to be solvedwas how to create an instance of a form class based on its name being retrievedfrom a Report table record, frmSalesReport for example. One approach that workswould be to use a Select Case statement to determine which form to launch:
Select Case lstReports.Text
Case "Sales Report"
Dim oCriteriaForm As New frmSalesReportCriteria
Case "Inventory Analysis Report"
Dim oCriteriaForm As New frmInventoryAnalysisCriteria
'Continue adding Case statements for each report
End Select
oCriteriaForm.ShowDialog()While this does work, the problemhere is that you would have to expand the Case statement with each new cannedreport added to the application. Again, the above works, but we can do better.
The objective is to be able to addnew records to the reports table without having to make any changes to thefrmReportListing form. We wanted to have code that would logically work likethis:
'Assign the form name to a string from a field or wherever. I’m hard
'coding form name here for simplicity sake
Dim CriteriaFormName As String = "frmSalesReport"
'Instantiate a form based on the value in the string above
Dim oCriteriaForm as New [FormName] <— This is what we want to accomplish
oCriteriaForm.ShowDialog()Just because I know someone willemail me saying “I tried to put the formname in brackets like you did but it doesn’t work”. I know… The above codewill not compile. It is only used to illustrate what I’m trying to accomplish.Ultimately the goal is to retrieve the form name to instantiate from somewhereand then dynamically instantiate it.
The solution we opted for implementsa factory design pattern. You pass in the name of the class to instantiate tothe CreateAnObject method and it returns an instance of that class.
Imports System.Reflection
Public Class ObjectFactory
'Code contributed by Rod Paddock (Dash Point Software)
'www.dashpoint.com
Public Shared Function CreateAnObject(ByVal ObjectName As String) As Object
Dim Assem = [Assembly].GetExecutingAssembly()
Dim myType As Type = Assem.GetType(ObjectName.Trim)
Dim o As Object = Nothing
Try
o = Activator.CreateInstance(myType)
Catch oEx As TargetInvocationException
MessageBox.Show(oEx.ToString)
End Try
Return o
End Function
End ClassA simple Messagebox.Show() call isplaced in the catch to keep things simple. How to handle an exception is notthe focus of this article.
In order to use the ObjectFactoryabove you just pass a string in the format “assembly.classname” like this:
Dim oForm As Form = _
ObjectFactory.CreateAnObject("MyApplication.frmSalesReport")
oForm.Show()In the above code “MyApplication” isthe assembly name for the project and “frmSalesReport” is the name of thereport filtering criteria form being displayed. Note though that while I usedthe object factory to create a form, you can pass in any type to the factoryand have it instantiate an object of that type for you.
In our project we simplyconcatenated the name of the project assembly with the form name of theselected report and passed that into the object factory like this:
'Grab the form name from the array used to populate the list box
Dim ReportFormToShow As String = _
"ProjectAssemblyNameHere." + oReports(0).Item(1)
'Pass the form name into the object factory and show the form
Dim oForm As ReportForm = ObjectFactory.CreateAnObject(ReportFormToShow.Trim)
oForm.ShowDialog()Go ahead and give it a shot.
1) Create a WinForm applicationnamed MyApplication.
2) Create a new class namedObjectFactory and copy the class code above into it.
3) Create a new form named frmTwoand change its height and width to distinguish it a bit.
4) Add a button to Form1 and addthis code in the code behind:
Dim oForm As Form = ObjectFactory.CreateAnObject("MyApplication.frmTwo")
oForm.Show()5) Run the application and click onthe button on Form 1. It should launch form frmTwo.
Tada!
Another real world usage scenariomight be capturing the name of the last form used by a user and have that formautomatically displayed the next time the user opens the application. Forexample, consider an accounting application with forms like frmVendors,frmCustomers, frmDeposits and so on. When the user exits the application thename of the active form could be stored in a table or an XML file or anywhereelse you choose to store that information. The next time the user logs on tothe application the last used form name value is retrieved and then passed tothe object factory to create an instance of that form. The uses of thistechnique are endless.
Hopefully this will help you createmore flexible and dynamic applications.
A HUGE thank you goes out to my friend, software development businesspartner, Yoda to my Luke Skywalker, CoDe Magazine Editor,and Microsoft MVP RodPaddock for his help with this article. Iknew exactly what I wanted to accomplish and he knew exactly how to accomplishit. It’s good to have friends you can rely on for help. Thanks a ton Rod!
About Jim Duffy:
Jim Duffy is founder and president of TakeNote Technologies, anaward-winning training, consulting, and software development companyspecializing in .NET software developer training and helping clients createbusiness solutions with Microsoft enterprise. Jim's expertise is with VisualStudio, Visual Basic, ASP.NET, SQL Server and Visual FoxPro-to-.NETconversions. He has a BS degree in Computer and Information Systems and over 25years of programming and training experience. He is an energetic trainer,skilled developer, and has been published in leading developer-orientedpublications.
Jim is a Microsoft RegionalDirector, a Microsoft MVP award recipient since 2003, an INETA speaker, and isan entertaining and popular speaker at regional user groups and internationaldeveloper conferences. He is also a co-host of Computers 2K9, a call-in radioshow on WRBZ (AM 850), 850 The Buzz, in Raleigh, NC.