I have third party control called TopicBar which looks like window xp navigation bar that you can see on the left side of a window
In my application I've 71 forms I have created a DB table to store all my forms Name and Text,A partcular user can add which forms(by searching form's name that I have already stored in a table) should add in topicbar as item.
For example, A form called FrmBill and its name is Bill once a user addes Bill to Topicbar it will successfully creates an item with name Bill,Now what I'm facing is I need to open the form FrmBill when that user clicks on Bill item in topicbar
I can get form name ie FrmBill is a user clicks in Bill but I couldnt open the form becuase I need to dynamically create instance or call Form here frmBill
what I have done so far
Dim formName As String
Dim frm As Form
Using conn As New SqlConnection(conn_str)
conn.Open()
Dim cmd As SqlCommand
cmd = New SqlCommand("", conn)
cmd.CommandText = "select top 1 formname from winforms where id=" & winformid & ""
formName = cmd.ExecuteScalar
'output: FrmBill
frm = New Form
frm.Name = formName '(FrmBill)
With frm
.MdiParent = FrmMain
.Show()
.Focus()
End With
End Using
Note: in this function I can get form name ie FrmBill from the DB, but its not showing the actual form FrmBill
So is there anyways to declare form name like below
dim frm as new "& formname &"
It's not so easy as "dim frm as new "& formname &"", but it can be done doing something like this:
Dim frmNewForm As Form = Nothing
Dim frmNewForm_Type As Type = Type.GetType("your_assembly.type_name")
frmNewForm = CType(Activator.CreateInstance(frmNewForm_Type), Form)
I mean, you have to store the Type of the class form.
Edit:
You can open a form so:
Dim oFr as New frmBill
oFr.Show()
ok? Well. You can open a Form so:
Dim oFr as Form
oFr = New frmBill ' Because frmBill inherits System.Windows.Forms.Form class. All forms do it
oFr.Show()
Here, frmBill its the Type of the class. You have no frmBill explicit reference, so you have to load it dinamically.
How can be do? Using a "NET mechanism" called Reflection. You can create a class dinamically, specifing the class Type.
Dim frmNewForm As Form = Nothing
Dim frmNewForm_Type As Type = Type.GetType("project_name.frmBill")
frmNewForm = CType(Activator.CreateInstance(frmNewForm_Type), Form)
What is Plutonix saying? Suppose you have a public "Print" method in frmBill.
With my answer, you can't do this:
frmNewForm.print()
Because you only can access to System.Windows.Forms.Form methods (close, show, showdialog...)
You can improve this, using a custom base class, or using Interfaces, or base abstract class... as you need. You can combine different ideas, depending on what you need. For example, you can combine an Interface with a Superclass:
public class frmMyForms
inherits System.Windows.Forms.Form
public sub store_data ()
....
public interface IInterface_common_methods
sub print ()
...
public class frmBill
inherits frmMyForms
implements IInterface_common_methods
public overloads sub store_data ()
msgbox ("store")
end sub
public sub print () implements IInterface_common_methods.print
msgbox ("print")
end sub
Now, you could do things like:
Dim frmNewForm As frmMyForms= Nothing
Dim frmNewForm_Type As Type = Type.GetType("project_name.frmBill")
frmNewForm = CType(Activator.CreateInstance(frmNewForm_Type), frmMyForms)
frmNewForm.Show()
frmNewForm.store_data()
ctype(frmNewForm, IInterface_common_methods).Print()
I don't know if this is wthat you're looking for, but I hope this can help you to learn more about NET possibilities.
Dim str As String = "NAME OF FORM"
Dim formName As String = Me.GetType().Namespace & "." & str.ToString()
Dim form = CType(Activator.CreateInstance(Type.GetType(formName)), Form)
form.StartPosition = FormStartPosition.CenterScreen
form.Show()
This is what I do to dynamically load a form based on user interaction.
I hope this helps someone.
Related
Basically, I am rewriting some code working for years. Over the time I have many (60+) references to forms - there's a menuitem with OnClick event for each form, where a form reference was created:
Private Sub SomeForm_Click(sender As Object, e As EventArgs) Handles MenuItemForSomeForm.Click
NewTab("Some Form", New SomeForm, 0)
End Sub
...where first parameter is a name to put in a tabPage.Text where the form is opened, second is a new instance of the (particular) form SomeForm and 0 is a default record to display (0 means no default record).
Now, I created a dynamic menu and stored the form names in a database (due to better access control over the access rights, etc). Now, because the menu is generated at runtime, I can't have the OnClick event with separate instance definition of the form and have to create it at runtime, after the MenuItems are created. The side-effect idea was to cut the code short by using only 1 OnClick event or such with MenuItem.Tag paremeter as FormName. Something like:
Private Sub clickeventhandler(sender As Object, e As EventArgs)
Dim tsmi As ToolStripMenuItem = CType(sender, ToolStripMenuItem)
Dim newForm As New >>>FormFrom(tsmi.Tag.ToString)<<< ' only explanation, this won't work
MainW.OpenModuleInTab(new newForm, tsmi.Tag.ToString, 0)
However I am failing to find a way to create form (instances) from this string reference. Reference through collection (i.e. List(of) or Dictionary) would be fine too, I believe.
The structure is obviously:
Object → Form → Form1 (class) → MyForm1 (instance)
I know I can create an object like this:
' Note that you are getting a NEW instance of MyClassA
Dim MyInstance As Object = Activator.CreateInstance(Type.GetType(NameOfMyClass))
I can re-type it to a Form type:
Dim NewForm as Form = CType(MyInstance,Form)
... to acccess some of the form properties like Width, TopLevel, etc., but that's about it. I can't do:
Dim NewForm1 as Form1 = CType(NewForm,Form1)
...because obviously, Form1 comes as a string "Form1".
I don't know how to create a Form1 reference from a "Form1" text (then it would be easy to create an instance) or how to create an instance directly (MyForm1).
SOLUTION
As sugested, I used reflection to get the form. The only way working for me I found was this:
Dim T As Type = System.Type.GetType(FormName, False)
If T Is Nothing Then 'if not found prepend default namespace
Dim Fullname As String = Application.ProductName & "." & FormName
T = System.Type.GetType(Fullname, True, True)
End If
Dim f2 As New Form ' here I am creating a form and working with it
f2 = CType(Activator.CreateInstance(T), Form)
f2.TopLevel = False
f2.Name = FormName.Replace(" ", "") & Now.ToString("yyyyMMddmmhh")
f2.FormBorderStyle = FormBorderStyle.None
f2.Dock = DockStyle.Fill
I am using VB.net CallByName to set public variable and same function to run a sub method (every form contains RecordID variable and LoadRecords sub):
CallByName(f2, "RecordID", CallType.Set, 111)
CallByName(f2, "LoadRecords", CallType.Method, Nothing)
For testing purposes, I put following into the testing form:
Public RecordID As Int32
Public Sub LoadRecords()
MsgBox("Load records!!!!" & vbCrLf & "RecordID = " & RecordID)
End Sub
Activator.CreateInstance(TypeFromName("Form1"))
TypeFromName Function:
Dim list As Lazy(Of Type()) = New Lazy(Of Type())(Function() Assembly.GetExecutingAssembly().GetTypes())
Function TypeFromName(name As String) As Type
Return list.Value.Where(Function(t) t.Name = name).FirstOrDefault()
End Function
So, let's go with the idea that I have an assembly called "WindowsApp2" and in that assembly I've defined Form1 and Form2. I've also created this module in the same assembly:
Public Module Module1
Public Function GetDoStuffWiths() As Dictionary(Of Type, System.Delegate)
Dim DoStuffWiths As New Dictionary(Of Type, System.Delegate)()
DoStuffWiths.Add(GetType(WindowsApp2.Form1), CType(Sub(f) WindowsApp2.Module1.DoStuffWithForm1(f), Action(Of WindowsApp2.Form1)))
DoStuffWiths.Add(GetType(WindowsApp2.Form2), CType(Sub(f) WindowsApp2.Module1.DoStuffWithForm2(f), Action(Of WindowsApp2.Form2)))
Return DoStuffWiths
End Function
Public Sub DoStuffWithForm1(form1 As Form1)
form1.Text = "This is Form 1"
End Sub
Public Sub DoStuffWithForm2(form2 As Form2)
form2.Text = "This is Form 2"
End Sub
End Module
Now, in another assembly "ConsoleApp1" I write this:
Sub Main()
Dim DoStuffWiths As Dictionary(Of Type, System.Delegate) = WindowsApp2.Module1.GetDoStuffWiths()
Dim formAssembly = System.Reflection.Assembly.Load("WindowsApp2")
Dim typeOfForm = formAssembly.GetType("WindowsApp2.Form1")
Dim form As Form = CType(Activator.CreateInstance(typeOfForm), Form)
DoStuffWiths(typeOfForm).DynamicInvoke(form)
Application.Run(form)
End Sub
When I run my console app I get a form popping up with the message "This is Form 1".
If I change the line formAssembly.GetType("WindowsApp2.Form1") to formAssembly.GetType("WindowsApp2.Form2") then I get the message "Wow this is cool".
That's how you can work with strongly typed objects that you dynamically instantiate.
Dim AssemblyProduct As String = System.Reflection.Assembly.GetExecutingAssembly().GetName.Name
Dim FormName As String = "Form1"
Dim NewForm As Object = Reflection.Assembly.GetExecutingAssembly.CreateInstance(AssemblyProduct & "." & FormName)
If TypeOf (NewForm) Is Form1 Then
Dim NewForm1 As Form1 = CType(NewForm, Form1)
NewForm1.BackColor = Color.AliceBlue
NewForm1.Show()
End If
Hello again StackOverflow community.
I need to add text to an externally generated form into TextBox.
My Code (For generating new form):
Public Sub NewPage()
Dim newtab As New CenterForm1
newtab.MdiParent = Me
newtab.Show(DockPanel1)
newtab.ComID.Text = newtab.codeblock.Name
newtab.codeblock.Name = +count
newtab.Name = +count
count += 1
End Sub
My Code (for insert text to TextBox):
Dim GetActive As GetActiveWindow
Dim codeblock As New TextBox
GetActive.codeblock.Text = "TESTIIIING"
Code for "GetActivateWindow" class
Imports WeifenLuo.WinFormsUI.Docking
Public Class GetActiveWindow
Public Property codeblock As TextBox
Public Function GetActive()
'Verify if forms that dock in main window are already open
For Each form As DockContent In Form1.DockPanel1.Contents
If form.DockHandler.Pane.ActiveContent.DockHandler.Form.Name.ToString() = form.Name.ToString() Then
Dim formName As String = form.Name.ToString()
Return formName
End If
Next
Return Nothing
End Function
End Class
Any ideas?
In my application I have to show lot of forms when particular button/panels are clicked. so instead of writing
Frm = New formname
Frm.MdiParent = MDIParent
Frm.Show()
i want to have public function through which i can pass the form name.
for that i have written a function
Public Sub showForm(ByVal formname As Form)
Frm = New formname
Frm.MdiParent = MDIParent1
Frm.Show()
End Sub
Call showForm(myformname)
but problem with this is, it says formname is not defined
EDIT:
I updated my answer to reflect your comment that a form should only be opened once.
I want to have public function through which i can pass the form name.
for that i have written a function
Public Sub showForm(ByVal formname As Form)
You don´t pass the name of a form to your function but an object of type Form instead.
Here is one possible solution with a generic version of showForm:
Public Class FormManager
Private _formByName As New Dictionary(Of String, Form)
Public Sub showForm(Of T As {Form, New})(name As String, parent As Form)
Dim frm As Form = Nothing
If Not _formByName.TryGetValue(name, frm) OrElse _formByName(name).IsDisposed Then
frm = New T()
_formByName(name) = frm
End If
frm.MdiParent = parent
frm.Show()
End Sub
End Class
The FormManager holds a dictionary cache for all opened forms with Key=form name. This is to make sure that a form is only opened once. The check form.IsDisposed makes sure that you can close the form and reopen it.
Usage from the parent form:
Public Class Form1
Private fm = New FormManager()
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
fm.showForm(Of MyForm)("MyForm", Me)
End Sub
End Class
The first parameter is to identify the form name. The real magic is in the Type T which we made sure it is 1) of type or subtype Form and 2) it has a parameterless constructor (MyForm is just a placeholder for this example put in the type of your real form you want to show).
The parent parameter will bring you additional flexibility if it is not always MDIParent1. Remove it if you don´t neet the extra flexibility.
For sure you can also drop the FormManager class and put the showForm to another place.
I have an MDI Parentform and it has multiple forms which are declared as :
Partial Public Class Giriş
Private clients As thirdperson
Private suppliers As thirdperson
Private activecontrol As thirdperson
Private proposals As transactions
Private addproposal As addtransaction
private sales as transactions
private addsales as addtransation
Private products As products
...
...
I also have a dataworks sub which works as a class but i code it in form and also for each form as below :
'for example for pressing add new button
If ActiveControl Is **clients** Or ActiveControl Is **suppliers** Then
activeform.dataworks (counter, "add new")
ElseIf ActiveControl Is products Then
products.dataworks (counter, "add new")
ElseIf ActiveControl Is addproposal Then
addproposal.dataworks (counter, "add new")
End If
i need a way to figure out how to use a vairble name for instance name. (I don't want to define each instance name everytime i just want to know if there is a way to use like below :
'for example
dim formvariable as form
formvariable.dataworks(counter,"add new") --> just want to use this and assign the value for products, proposals vs to this variable.
is this possible?
Thanks for your help in advance.
Sertac.
The proper way would be to develop an Interface that all of your Child Forms Implement. That interface would have a dataworks() method. Then you can cast the current mdichild to the interface type and run the method. This would result in strongly typed coded that makes sense.
If you just want to hack your way through it, though, then attempt grab the dataworks() sub from the current mdichild using reflection and execute it like below:
Dim frm As Form = Me.ActiveMdiChild
If Not IsNothing(frm) Then
Dim MI As Reflection.MethodInfo = frm.GetType.GetMethod("dataworks", Reflection.BindingFlags.Instance Or Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Public Or Reflection.BindingFlags.IgnoreCase)
If Not IsNothing(MI) Then
MI.Invoke(frm, New Object() {counter, "add new"})
End If
End If
Here's a quick example of the Interface approach:
Public Interface Data
Sub DataWorks(ByVal counter As Integer, ByVal msg As String)
End Interface
This is what thirdperson looks like implementing the interface:
Public Class thirdperson
Implements Data
Public Sub DataWorks(counter As Integer, msg As String) Implements Data.DataWorks
Debug.Print(counter & ", " & msg)
End Sub
End Class
All of your mdichild forms would have to be modified in a similar approach.
Then the code in the MdiParent would change to:
Dim frm As Form = Me.ActiveMdiChild
If TypeOf frm Is Data Then
Dim D As Data = DirectCast(frm, Data)
D.DataWorks(counter, "add new")
End If
I'm writing a program that creates forms at runtime using this code,
Dim a As Integer = Screen.AllScreens.Length
Dim frm2(a) As Form
For b As Integer = 0 To a - 1
frm2(b) = new form
' ... set attributes to the form here
frm2(b).Show()
Next
My questions is how can I later from another sub access these forms? For instance if I wanted to draw graphics on these forms how would I access them? They're not available outside the subroutine that created them and you can't make a public array of controls in vb.net?
Just declare the frm2 array outside of your Sub method, at the class-level. For future reference, variables declared at the class-level are called fields. Fields are scoped to the class, so any method in the class can access them. For instance:
Public Class MyClass
Private frm2() As Form
Public Sub CreateForms()
Dim a As Integer = Screen.AllScreens.Length
ReDim frm2(a)
For b As Integer = 0 To a - 1
frm2(b) = New Form()
' ... set attributes to the form here
frm2(b).Show()
Next
End Sub
End Class
For what it's worth, I would recommend using a List(Of Form) rather than an array. That way you don't have to worry about re-sizing it, for instance:
Public Class MyClass
Private forms As New List(Of Form)()
Public Sub CreateForms()
For i As Integer = 0 To Screen.AllScreens.Length - 1
Dim frm2 As New Form()
' ... set attributes to the form here
frm2.Show()
forms.Add(frm2)
Next
End Sub
End Class
Rather than defining the forms in the sub itself, if you create them as form variables. Then you can access these from any sub within that form.
You should then be able to create whatever you need on the form, or preferably create a Public Sub on the form which can be called from elsewhere.