Private Sub tsGradovi_Click(sender As Object, e As EventArgs) Handles tsGradovi.Click
For Each f As Form In Application.OpenForms
If TypeOf f Is frmGradovi Then
f.Activate()
Return
End If
Next
Dim f2 As New frmGradovi
f2.MdiParent = Me
f2.Show()
f2.WindowState = FormWindowState.Maximized
resetdgvGradova()
End Sub
On this way i add the Child form to my main Form.
On that frmGradovi form i have the datagridview. Now i added class to my project.
How can i add the datagridview source from my class.
this code is not helping
frmGradovi.DGV.DataSource = SQLDataset.Tables(0)
Probabbly because frmGradovi is mdi child of form1.
Edit:
At class konekcija i need to set the datasource for the frmGradovi form. But that frmGradovi form is an mdi child form of Form1
One way to avoid these types of conundrums is not to write Form-centric code. They are basically a sandbox for collection user input. The other element is to explicitly instance forms: In your code f2 is an instance of frmGradovi. Trying to reference it as frmGradovi elsewhere risks creating a new default instance of it (you'd later have 2 forms of Type frmGradovi in your Forms collection).
I dont know what a Gradovi or a konekcija is, so I will use a Customer example. My app might have a frmCustomer and a Customer class. When it comes time to display a certain customer, rather than the MDI parent form code or button click creating the form, I'd leave that job to the Customer class:
Public Class Customer
' myFrm is an instance of frmCustomer, which is a Type
Private myFrm As frmCustomer
Private myDT As DataTable
Public Sub Display(Id As Int32)
CustId = Id
If myFrm Is Nothing Then
myFrm = New frmCustomer
' MDI boilerplate code
'...
' one time setup code like populate static CBOs:
'...
End If
UpdateDisplay()
myFrm.BringToFront()
End Sub
Public Sub UpdateDisplay()
' display code when something changes such as show new selected Customer
' e.g.:
LoadCustDataToDataTable(CustId)
With myFrm
.tbfirstName.Text = FirstName
.tbLastName.Text = LastName
' ...etc
.dgvPastOrders.DataSource = myDT
End With
End Sub
The "key" is that the Customer class is in charge of the customer form. It creates it and retains a reference to it. When the user clicks Save that task too would be offloaded to the Customer.Save method.
You'll have other gyrations to add to handle when the user closes that form (if they are allowed to close versus just hiding it). In your current approach, your class could fish the reference to its form from the collection as it needs it.
Related
Form Name comes from a variable. I would like to open Form from variable value.
In VBA load("UserFormName") will show the form. But I don't know how to do it in VB.Net.
Ok, of course one would want to be able to open a form by string name.
When you create a vb.net winforms project, then all forms are available as a "base" static class.
You often see a LOT of code thus simply use the base form class.
If I need to display say form2, then I really don't need to create a instance of that form (unless you want to have multiple instances of that form. So a truckload of code will simply launch + use the "base static" class of that form.
eg:
Form2.Show()
I don't consider this all that bad of a practice, since what do you think the project settings to "set" the startup form in the project settings does?
It simply sets the built in instance of "mainForm" = to your startup form and it does NOT create new instance.
So, now that we all can agree for 15+ years anyone who has set the startup form in their project is NOT creating a NEW instance of that form, but in fact using the base class instance. This is really a programming choice.
So, code to display (show) the base static instance of a form by string name will look like this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim strForm As String = "Form1"
ShowFormByName(strForm)
End Sub
Public Sub ShowFormByName(strFormName As String)
System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(ProductName & "." & strFormName).show()
End Sub
Private Function FormByName(strFormName As String) As Form
Return System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(ProductName & "." & strFormName)
End Function
However, above includes a helper sub that will simply "show" that built in instance of the forms.
And above also includes a function to return class type of the form, since for sure a good many developers prefer to first create a instance of the form, and then "show()" it.
So, often we do want multiple instances, or we just perfer the codeing approach of creating a new instance of the form object.
So, we use the 2nd helper function to return a form object of the type we passed by string.
So, to display 3 instances of form1, but the FIRST instance being the base class, then two more but brand new instances of that form, we have this code:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim strForm As String = "Form1"
ShowFormByName(strForm)
Dim f1 As Form = FormByName(strForm)
Dim f2 As Form = FormByName(strForm)
f1.Show()
f2.Show()
End Sub
So the above code snip shows how to display the built in base class form without having to create a instance of that form.
However, the next two forms we load are "new" instances of that form as "string".
So the helper sub, and helper function will give you both choices as to which preference floats your boat.
Dim form = System.Reflection.Assembly.GetExecutingAssembly().CreateInstance(Application.ProductName & "." & MySubForm)
Dim frm As New Form
frm = form
frm.MdiParent = AFrmMainScreen
frm.WindowState = FormWindowState.Maximized
frm.Show()
I prefer to use Reflection.Assembly.GetEntryAssembly because I use several different projects in one solution. This allows me to put this code in a different project(dll) that has a usercontrol that I can then reuse across multiple solutions. You also don't need to know the "Namespace" for the form as long as it is in the startup project.
The code below gets the form type from the exported types from the entry assembly and then uses Activator.CreateInstance to create a new instance of the form. Then I return that form in the function.
Public Function GetForm(ByVal objectName As String) As Form
Try
Dim frmType = Reflection.Assembly.GetEntryAssembly.GetExportedTypes.FirstOrDefault(Function(x) x.Name = objectName)
Dim returnForm = TryCast(Activator.CreateInstance(frmType), Form)
Return TryCast(returnForm, Form)
Catch ex As Exception
Return Nothing
End Try
End Function
To use the above function:
Dim MyForm = GetForm(FormLocation)
If MyForm IsNot Nothing Then
MyForm.ShowDialog()
'You can do any form manipulation from here.
Else
MessageBox.Show($"{FormLocation} was not found.")
End If
I currently have 2 forms. 1 holds user data and is modifiable. The other is a display/read only form.
I am trying to pull data (tbUSI.text) from ReportSettings and pass it to Form1 and display it on my UserData.text control.
I have tried using public properties but to no avail. I would rather use public properties, since its cleaner. Here is the code im using to set the property:
Public Property UserSignedInto As String
Get
Return tbUSI.Text
End Get
Set(value As String)
End Set
End Property
Here is my code attempting to call that property on the main form (form1)
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
UserData.text = UserSignedInto
End Sub
It doesn't pull anything, the textbox on my main form is blank.
Take a look here:
SCCMReports = New ReportSettings
UserData.text = SCCMReports.UserSignedInto
When was the SCCMReports form ever displayed to the user? Since it was never displayed, its tbUSI.Text value will of course be empty because the user never had an opportunity to enter text.
It sounds like you need a reference to an existing instance of ReportSettings, rather than creating a new instance. Where do you have that existing instance?
If Form1 created the instance in another block of code, store it in a class-level member on Form1 (perhaps called SCCMReportsInstance or something of that nature). When the instance is created, set it to the value of that property and reference that property in your code:
UserData.text = Me.SCCMReportsInstance.UserSignedInto
If the ReportSettings form is instead creating the instance of Form1 then it can pass a reference to itself. You'd still have a property on Form1, it would just be set in the constructor. Something like this:
Sub New(ByVal sccmReportsInstance As ReportSettings)
Me.SCCMReportsInstance = sccmReportsInstance
End Sub
So when initializing the Form1 instance, you'd pass the reference:
Dim form1 As Form1
form1 = New Form1(Me)
form1.Show()
Any way you go about it, you need to access the existing instance of the displayed form in order to access its properties. A new instance would have new versions of those properties and wouldn't have the same values.
I was wondering how you would grab some text from a textbox in a selected form. I have a MDI form which contains X number of child forms. Each child form has a textbox in it with some text. When I hit the save button how do I know which form is selected and how do I grab the text from that textbox.
Private Sub Forms_Clicked(sender As Object, e As EventArgs) Handles Forms.clicked
globalVar = sender
End Sub
I was thinking to make an event that just detects when ever a form is clicked and save it's form/form ID in a global variable. Any thoughts?
You have to determine the active child from first and from there, you can check which text box you want to read its content.
Like bodjo said, you have the [YourMDIForm].ActiveMDIChild property.
What is unclear, like Plutonix said is where is your Save "Button". Did you meant :
a Save MenuItem from a MenuStrip on your MDI Parent Form ?
or a Save Button inside an MDI Child Form (or either another Form that is not part of the MDI Parent/Child system)
The first case is pretty straightforward : Use the .ActiveMDIChild of your MDIParent Form.
The secund may need some valid way to point to an actual active child form (similar to the one you tried with your globalVar... there are better ways to do it.
By the way, when you get your targeted MDIChild through .ActiveMDIChild, you must access the textbox with a Public, Friend or Protected variable. Usually, controls in forms are private. So you may have to :
Public Class [YourMDIChildClassName]
' ...
' create a Public Property
Public ReadOnly Property ContentToSave() As String
Get
Return [YourTextBox].Text
End Get
End Property
' or make your textbox public in the Form design
Public [YourTextBox] As TextBox
' ... the one or the other, not both.
' ...
End Class
Another way to access the "active" MDIChild, assuming all of your MDIChild are instances of the same class is to create a static (shared) property in your Child class :
Public Class [YourMDIChildClassName]
' ...
Private Shared _CurrentMDIChild As [YourMDIChildClassName] = Nothing
Public Shared ReadOnly Property CurrentMDIChild() As [YourMDIChildClassName]
Get
Return _CurrentMDIChild
End Get
End Property
' ...
End Class
And using the same thing you tried, but using .Activated instead of .Clicked
Public Class [YourMDIChildClassName]
' ...
Private Sub MyChildForm_Activated() Handles Me.Activated
_CurrenMDIChild = Me
End Sub
' And that's ALL this method SHOULD contain.
' If you try to add other activation tricks, like activating another Form,
' or firing up a DialogBox (worst case),
' everything will go WRONG and your application will hang in an endless loop !!!
' Be carefull when using .Activated.
' ...
End Class
Then you could access the currently active MDIChild using the static Property :
[YourMDIChildClassName].CurrentMDIChild
' => Gives you directly a VALID instance of your MDI Child (or Nothing !)
' Then you can use in your MDI Parent :
If [YourMDIChildClassName].CurrentMDIChild IsNot Nothing Then
Dim TextToSave As String = [YourMDIChildClassName].CurrentMDIChild.ContentToSave
' ... save your text...
End If
HOWEVER, because you've created a static (shared) pointer to the last active MDIChild (sort of, I know it's not a pointer like in C) you must update this pointer whenever you close an MDIChild Form !
Public Class [YourMDIChildClassName]
' ...
Private Sub [YourMDIChildClassName]_FormClosing( _
sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
If _CurrentMDIChild Is Me Then ' And "Me" is closing right now...
_CurrentMDIChild = Nothing
' We don't want memory leak or pointer to a Form that has been closed !
End If
End Sub
' ...
End Class
We are not supposed to create custom way of handling Child Form activation. MDIParent.ActiveMDIChild is there for that. However, once we want to access extended/custom/specific Properties of the Child Form that doesn't initially exists in System.Windows.Forms.Form, we need to cast the MDIParent.ActiveMDIChild to the real Form derived Type of our MDIChild. That's one other way to do it, but it's just me : I don't like castings much. Always set IDE to :
Option Explicit On
Option Strict On
Option Infer Off
Forms.Clicked ... does this event (Clicked) really exist ? I'm aware of .Click but not "Clicked". Anyway :
Public Class [YourMDIChildClassName]
' ...
Private Sub MyChildForm_Clicked() Handles Me.Click
' This part is executed when you click INSIDE the Form,
' at a location where there is NO Control.
' If you click on a control, like a Textbox, a Picturebox, a Panel, etc
' this block IS NOT EXECUTED as you've clicked on a control,
' not on the Form !
End Sub
' ...
End Class
I have two forms, form 1 and form 2 (windows application). How can i access and check a checkbox in form 1 from form 2. Initially i tried calling the form name and then the control like form1.chkCanada.checked = true, it did not work. And then i added a property in form 1
Public Property abc As Boolean
Get
Return chkCanadianStmtInd.Checked
End Get
Set(value As Boolean)
chkCanadianStmtInd.Checked = value
End Set
End Property
and then in form 2
Dim frm As New frm1
frm.abc = True 'Checked
And it still doesnt work. Am i missing anything here?
Alternatively you can pass a handle of form1 to form2 constructor
Form1:
Public Class Form1
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
Dim _form2 As New Form2(Me)
_form2.Show()
End Sub
End Class
Form2:
Public Class Form2
Public Sub New(ByVal _form1 As Form1)
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
_form1.CheckBox1.Checked = True
End Sub
End Class
Consolidating comments here:
In order to access controls on a form that shows another form to the user you have two options, if no interaction is needed with the first form while the second form is active you can use showdialog and do all of your logic after the second form has closed, if you ned to maintain the ability to interact with the first form while the second is still open then you need to use custom events.
Showdialog:
The simpler of the two options is to switch your form.show() function calls to form.showdialog(). This effectively tells the first form that it should stop processing at the form.showdialog() line and wait for the child form to close before proceeding. Once the second form is closed the first form will pick up where it left off and that would be where any processing that relies on the values of the second form would take place.
Custom Events:
If you want to allow the user to interact with both the first and second forms at the same time then you will need to use custom events. In order to do this you will need three things. The custom event, a raiseevent call and an event handler.
So in your Form2 class you will need to declare the custom event. In this case since you are trying to check(or uncheck I assume) a box your custom event declaration will look like:
public event ChangeCheckedValue(byref state as boolean)
Now on your button click event you will need to raise the event to the handler on Form1:
RaiseEvent ChangeCheckedValue(booleanValue)
Now that those statements are in place you will need to changed your form2 object that is being shown by Form1. What I normally do is make Form2 a form wide variable on Form1 and declare it like:
private withevents frm as Form2
Once you have the frm variable in your Form1 class you can add a handler for the ChangeCheckedValue event:
protected sub HandleCheckChanged(byref bln as boolean) handles frm.ChangeCheckedValue
'Set the checked state of your checkbox.
End sub
Once you have all that set up you should see what you expect.
I have an MDI parent form that may open a child form called "Order". Order forms have a button that allows the user to print the order. The Order form has a print size variable defined at the beginning:
Public Class Order
Public psize As String
Private Sub button_order_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles process_order.Click
' Code to handle the order and then print, etc
Now the parent form has a psize variable as well, which is set to a default of "A4".
Only when someone clicks on one of the menu items on the Parent window's menu strip will this happen:
psize = "A6"
By default, whenever the parent window opens up a new Order form, I need it to set the child form's psize variable to its own psize value. Something like this:
Dim f As Form
f = New Order
f.MdiParent = Me
f.psize = Me.psize ' BUT THIS LINE DOESN'T WORK
f.Show()
I get the error that f.psize is not a member of the form.
I know that passing variables to and from the MDI parent and child is quite common but despite trying out a few options I saw here, it doesn't seem to be working. Is this the wrong approach?
The reason the property is not available is because you are using the wrong type for the variable. The base Form type does not define that property. Instead, your derived Order type does. You could do something like this:
Dim f As Order
f = New Order
f.MdiParent = Me
f.psize = Me.psize
f.Show()
UPDATE
As you have said in comments below, what you really need to do is to be able to share a dynamic setting between all your forms so that you can change the setting at any time and have it affect all your forms that have already been displayed. The best way to do that, would be to create a new class that stores all your shared settings, for instance:
Public Class Settings
Public PaperSize As String = "A6"
End Class
As you can see, by doing so, you can easily centralize all your default settings in your settings class, which is an added benefit. Then, you need to change the public property in your Order form to the new Settings type, for instance:
Public Class Order
Inherits Form
Public Settings As Settings
End Class
Then, you need to create your shared settings object in your MDI Parent form, and then pass it it to each of your Order forms as they are created:
Public Class MyParentForm
Private _settings As New Settings()
Private Sub ShowNewOrderForm()
Dim f As New Order()
f.MdiParent = Me
f.Settings = _settings
f.Show()
End Sub
Private Sub ChangePaperSize(size As String)
_settings.PaperSize = size
End Sub
End Class
Then, since the parent form and all the child Order forms share the same Settings object, and change made to that Settings object will be seen immediately by all the forms.
Change this:
Dim f As Form
to the actual implementation of your form:
Dim f As Order
or just the shortcut:
Dim f As New Order