I know, that there are many questions related to this, but still I cannot find a workable solution.
Usually, it would work like this: A form creates an instance of another form in it's container like this:
Dim PolInstIn As New SubForm1
Private Sub LoadDetail()
PolInstIn.TopLevel = False
PolInstIn.Name = "Sub From"
PolInstIn.FormBorderStyle = Windows.Forms.FormBorderStyle.None
PolInstIn.Dock = DockStyle.Fill
Me.GroupBox6.Controls.Add(PolInstIn)
PolInstIn.Show()
End Sub
Then it's easy to call a Public Sub from the sub form like this:
Call PolInstIn.MyPublicSubInSubForm1()
However, this doesn't work for me in this case. When I run MyPublicSubInSubForm1() it doesn't throw any error, but does no action. If I write a value to SubForm1 textbox and read it back, it reads, but I don't see it on the screen, so I suspect it is written to some other accidental instance.
I suspect it is because my parent form is also an instance of an form created in very similar way like SubForm1. Basically the ParentForm is a form loaded into tabPage and SubForm1 is a module loaded into ParentForm. It can exist in many copies (tabs).
Could you point to any simple solutions?
Regards,
Libor
I see this question got a lot of views, so here is an answer.
1) No visual response of child form (only results) - this could have happened if I created more then 1 instances of the form. The example is just an example, but if one use it (accidentally) this way, it may result in new definition of a child form every time (and consequent symptoms like the ones described). In practice, I split form loading from loading data into to the form (done by a public sub in that form).
2) If you want also a back reference (to i.e. parent grid form), define a Public ParentFormGrid as GridName (note ParentForm is a reserved name) and on loading a child form, set
PollInstIn.ParentFormGrid = Me
This way you can alway asccess the parent form, i.e. reload the grid when you save changes on a line edited in child form.
make Private Sub LoadDetail() to a public :
Public Sub LoadDetail()
It work on my project. Hopely its what you want
Dim PolInstIn As New SubForm1
Private Sub LoadDetail()
PolInstIn.Name = "Sub From"
PolInstIn.Show()
PolInstIn.TopLevel = False
PolInstIn.FormBorderStyle = Windows.Forms.FormBorderStyle.None
PolInstIn.Dock = DockStyle.Fill
PolInstIn.Update()
PolInstIn.Refresh()
Me.GroupBox6.Controls.Add(PolInstIn)
End Sub
Related
I am learning vb.net and I'm having issues searching for what I need. I want to create a button that is "re-usable" throughout my application without needing to write code for each instance. So, what I would like to start with is take a variable in a form, example, public integer value and when this value changes I want to write to the text of a button. I know I can easily do this by writing code in the form btn_xxx.text = variable, but what if I have several buttons and each button looks at the same variable? Currently what I do is create a component which inherits a button and have a timer that on tick will look at the variable and write to the text. I'm sure there is a better way. Can anyone point me in the right direction? I know part of my problem is I don't know the nomenclature on what things are called, so hopefully I asked my question without too much confusion.
I saw this, https://www.daniweb.com/programming/software-development/threads/124842/detect-variable-change, but I don't see how to adapt that to my situation.
Here is what I have:
Private WithEvents Active_Alarm As New Nav_Active_Alarm
Then inside of a sub that calculates the count:
Active_Alarm.Count = CInt(dt_Active_Alarms.Rows.Count)
The user control:
Public Class Nav_Active_Alarm
Private mActive_Alarm_Count As Integer
Public Event Active_Alarm_Count_Changed(ByVal mvalue As Integer)
Public Property Count() As Integer
Get
Count = mActive_Alarm_Count
End Get
Set(ByVal value As Integer)
mActive_Alarm_Count = value
If Not Me.DesignMode Then
RaiseEvent Active_Alarm_Count_Changed(mActive_Alarm_Count)
test()
End If
End Set
End Property
Private Sub test()
If Not Me.DesignMode Then
If mActive_Alarm_Count = 0 Then
Me.btn_Goto_Active_Alarm.Image = My.Resources.Alarm_Clock_Static
'console or msgbox will work but updating the image will not
Else
Me.btn_Goto_Active_Alarm.Image = My.Resources.Alarm_Clock_Animation
'console or msgbox will work but updating the image will not
End If
End If
End Sub
End Class
If I write to console or add a msgbox I will see the event working. But, the image will not change. If I call the test sub from a timer it will work. Why won't the button update (by the way, I did try refresh and update in the code)?
Observer pattern is what you probably looking for.
This is quick and dirty.
Create a class to hold the variable value. Add a method that adds a button instance to a list.
Then a button that needs to know about the variable calls the register method.
When the value of the variable changes, it iterates through the list of buttons and sets the Text property of each one.
You might have jumped in a bit too deep too quick here. Google Custom data binding in .net, there's loads of built in stuff you can use. Though do it yourself is a good exercise.
A simple method to do this might be:
Create a form level list to hold the buttons you are interested in
Add the buttons you are interested in, into the list (maybe in form load or some other place where you have initialization code)
Create a private property in your form with a backing variable to hold the value you want to have applied to the buttons. In the setter portion spin through the list and set each buttons text.
Dim lstButtons As New List(Of Button)
Sub SetupButtons()
'call from form load or other init code
lstButtons.Add(btnPopulate)
lstButtons.Add(btnPopulate)
End Sub
Private _buttonText As String
Private Property ButtonText As String
Get
Return _buttonText
End Get
Set(value As String)
_buttonText = value
For Each b As Button In lstButtons
b.Text = value
Next
End Set
End Property
When you set the property - which now acts as your variable - it will update all of your textboxes for you.
I realize you mentioned without having to write code - but something has to tie things together. Even if you used the observer pattern (which is an elegant solution for this - so props to those who suggested it) you'd probably end up creating a class to hold the property and have that class implement the INotifyPropertyChanged from System.ComponentModel, and then you'd also have to have each button have a databinding for its text property to the property in the object of your class. There isn't really a way (that I can think of) to get around having to write some code for each form you do this in (though the class part you'd only have to write once of course).
I am a newcomer to Visual Studio 2013, so my question is probably -and hopefully- a simple one.
I am currently writing a small program (in VB) that will essentially add/update/delete users from a table.
The main form has three TextBoxes (ID#, name, last name), a button to check if the user already exists and a couple more buttons (Save and Cancel)
I have also created a Class (dataLookup) where all the functions for adding, updating or deleting users are stored.
The way the program works is as follows:
1.- The user enters an ID# in the main Form's ID field and clicks on the "check user" button.
2.- The system calls a function stored in the datalookup Class that verifies if the ID# already exists.
3.- If it does, the function retrieves the name and last name from the table, assigns them to two local variables (vName and vLastName) populates the corresponding fields on the Main Form and returns TRUE. User can then either update data or Cancel (See code sample below)
MainFormName.TextBox1.Text = vName
MainFormName.TextBox2.Text = vLastName
return True
4.- If the ID# doesn't exist, the function returns FALSE. User is then able to enter new data in the three textboxes.
My problem is that I can't populate the TextBox fields from the function stored in the dataLookup Class. After the instructions are processed, the TextBoxes (which are both Enabled and have their Read Only property set to false) remain empty.
If I add the exact same code that populates the fields to the Main Form code, and assign values to the vName and vLastName variables, it works perfectly:
vName = "John"
vLastName = "Doe"
MainFormName.TextBox1.Text = vName
MainFormName.TextBox2.Text = vLastName
FYI, no errors are reported when I compile/run the program.
I am aware that I can modify the function so it will also return the name and last name and then I will be able to update the TextBox fields from the Main Form, but I am just curious: Why can't I do that from the function stored in the Class?
Hope my description was reasonably clear :) Any help will be much appreciated. Many thanks in advance!
Randy
Forms are classes (it says so at the top of each of them):
Public Class MainForm
....
As a class, an instance should be created however, VB allows what is called a default instance using the class name: MainForm.Show()
Under the hood, the compiler creates an instance of MainForm named MainForm and uses it. This is handy for developers hobbyists dabbling in code, but there are numerous ways this can bite you:
Sub DoSomeThing()
Dim frm As New Form1
frm.TextBox1.Text = cp.ToString
End Sub
Here a local instance of Form1 is created and used which has no relation to the Global Form1 which VB created. The local object goes out of scope at the end of the Sub never to be used by the rest of the app.
' in sub main:
Application.Run(New Form1) ' main form/pump
... elsewhere
Form1.TextBox1.Text = "hello, world!"
In spite of using the same name, these are actually different instances. The text will not show up and if the next line was Form1.Show(), a second copy of Form1 would display complete with the 'hello, world' text. These will also create/show new instances:
Form2.Show()
' or
Dim frm As New Form2
frm.Show()
In general, the more complex the app, the less appropriate using default instances is. For serious apps, create explicit form instances:
Dim myFrm = New Form7() ' myFrm is an instance of Form7
...
myFrm.TextBox1.Text = vName
myFrm.TextBox2.Text = vLastName
myFrm.Show
Classes or other forms can be told about this form various ways such as via a property or the constructor:
Class Foo
Private myFrm As Form7
Public Sub New(frm As Form7)
myFrm = frm
End Sub
...
End Class
Dim myFoo = New Foo(Me)
For the main/startup form, it can help to create a global reference:
Module Program
Friend frmMain As MainForm
End Module
Then set the variable when the main form loads:
Public Class MainForm
Private Sub MainForm_Load(sender ...)
frmMain = Me
End Sub
...
frmMain will be a valid reference to the main form for the entire application.
I am trying to implement another form into already complete routine. Basically all the code is there, all I need to do is manipulate the data in a different manner.
I have a routine that looks like this for instance.
This is a paraphrase example:
Private Sub getReportValues(ByRef fr As frmCustomReport, ByRef ReportInfo As ReportValues)
ReportInfo.eHeaderColor = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("Software\FE Jupiter\MSSMonitor").GetValue("Report Equipment Header Color", "DCDCDC") 'Gainsboro
ReportInfo.mHeaderColor = Microsoft.Win32.Registry.CurrentUser.CreateSubKey("Software\FE Jupiter\MSSMonitor").GetValue("Report Monitor Header Color", "FFF8DC") 'Cornsilk
fr.btnEquipColor.PickedColor = System.Drawing.ColorTranslator.FromHtml("#" & Microsoft.VisualBasic.Conversion.Hex("&HFF" & ReportInfo.eHeaderColor))
The problem lays with the (fr as frmCustomReport) I want to make it a system.windows.forms.form but then I would lose the ability to use its objects. I should also mention that fr is a modal dialog and that I don't want a really hacky controlcollection work around for this. Does anyone have a good direction on this?
Note Also!!! The controls I want to access on both forms are almost identical. The only diffrence is layout and some added functionality.
Without a little more information,it is a little hard to give a concrete example. This will work depending on the amount of interaction you need to do. Create a subroutine that accepts the Base Class as an argument, take a look at the Name value and base your conditional logic off of that using CType to cast the Form to the proper type.
Private Sub clickOtherFormsButton(Value As Form)
If Value.Name = "Form3" Then
Dim formObject As Form3 = CType(Value, Form3)
formObject.Button1.PerformClick()
ElseIf Value.Name = "Form2" Then
Dim formObject As Form2 = CType(Value, Form2)
formObject.Button1.PerformClick()
End If
End Sub
I want create one form from another. But the Form class has no the Show method, which described at http://msdn.microsoft.com/en-us/library/office/gg251540.aspx
It's code in Form_Main:
Private Sub btnTemp_Click()
Dim frmOpt As Form_Option
Set frmOpt = New Form_Option
frmOpt.Show vbModal
End Sub
But I received the "Compile error: Method or data member not found".
Where I made mistake?
Thanks
(VBA version 6.5; Access 2007)
=====
Sorry for my previous comment: right now I see that comment isn't obvious.
I don't have subForm on my mainForm.
I have two simple form: Form_Main and Form_Option. And I want to be the next logic:
Form_Main has button "btnOption"
Click on "btnOption". The Form_Option is opening
I change options on Form_Option
And click the btnSave button on Form_Option, and the next idea is executing:
Form_Main.TimerInterval = CLng(Form_Option.edtTimerInterval.Value)
At the moment I made it simple. And that is enough for me.
I write so:
Private Sub btnOptions_Click()
' After changing options, refresh timer interval of main form
DoCmd.OpenForm "Options", , , , , acDialog
Me.TimerInterval = 1000 * CLng(MOptions.loadOption("fPeriodVerifyNoticeInterval"))
End Sub
Where fPeriodVerifyNoticeInterval is parameter that stored in the options table.
And the Options Form changes the "fPeriodVerifyNoticeInterval" parameters at saving.
My problem is solved, Thanks
The "mistake" is that Show isn't a valid Method for Access Forms. The link you provided is for UserForms which are forms made in VBA.
If you want to create a new form that way what you want is something like this:
frmOpt.Modal = true
frmOpt.Visible = true
Though what I would recommend is doing this instead:
DoCmd.OpenForm "Option", , , , , acDialog which will open the Option form as a dialog.
Caution: If you create your form using New even though you set it as modal it will not halt the progress of VBA code. This means that your variable will go out of scope as soon as the code finishes. If you want your form to remain open, you will need to set it as static within the sub or declare it outside the sub like this:
static frmOpt As Form_Option
or outside the sub private frmOpt = Form_Option or public frmOpt = Form_Option
make my own UserControl and I can aggregate new TabPages to a TabControl and then, inside of then TabPage, I add my own UserControl using the following code.
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim TabX As New Windows.Forms.TabPage("Tab " & TabCount.ToString) '(ConfiguracionTabPage)
Dim MyControl As New ClientesEmpresa
MyControl.Name = "Control" & TabCount.ToString
If ClientesTabControl.TabPages.Count = 10 Then
ClientesTabControl.TabPages.RemoveAt(9)
End If
TabX.Controls.Add(MyControl)
TabX.Name = "Tab" & TabCount.ToString
TabX.Text = "Tab" & TabCount.ToString
MyControl.TitularLbl.Text = "Coca Cola"
Me.ClientesTabControl.TabPages.Insert(0, TabX)
Me.ClientesTabControl.SelectedIndex = 0
TabCount += 1
End Sub
My user control have several Labels, TextBox and TabPages(inside of a TabControl).
Now I want to change some properties dynamically from the source code, but I don't know how to access them.
The most similar theme that I found is this How to Acces of an User control in c#, but, as the title says, is in C#, how I can do it in VB.NET?
Sorry, I just notice that the Enter key post the comment. :(
Thanks for your feedback, I understand what are you saying but I missing something in the middle.
When I create the control in running time in the above code I can access easily to the properties of the created object, in this case my UserControl, but I don't understand how to reach the properties of a particular instance of that control from outside of Button_Click; ie. another button_click event(second button)
I was thinking to use something like
Dim ControlList As Windows.Forms.Control() = Me.ClientesTabControl.TabPages(0).Controls.Find("ModeloLbl", True)
or
ClientesTabControl.TabPages(0).Controls.OfType(Of AlarmasVehiculo)()
But I'm stuck here.
------------------------------------- 3th post ---------------
Thanks Steve, I was resolved using "Control.Find" and a For Each but your solution is easier.
There's any way to get the name of the selected tab or I must to create an Array when I create the New TabPage?, the idea is to update the text of the controls inside of the selected tab only when is selected by the user or every 5 seconds but just the in selected one.
Thanks.
To borrow M4N's answer from the C# question, and translate it to VB:
Cleanest way is to expose the desired properties as properties of your usercontrol, e.g:
Public Class MyUserControl
' expose the Text of the richtext control (read-only)
Public ReadOnly Property TextOfRichTextBox As String
Get
Return richTextBox.Text
End Get
End Property
' expose the Checked Property of a checkbox (read/write)
Public Property CheckBoxProperty As Boolean
Get
Return checkBox.Checked
End Get
Set (value As Boolean)
checkBox.Checked = value
End Set
End Property
'...
End Class
In this way you can control which properties you want to expose and whether they should be read/write or read-only. (of course you should use better names for the properties, depending on their meaning).
Another advantage of this approach is that it hides the internal implementation of your user control. Should you ever want to exchange your richtext control with a different one, you won't break the callers/users of your control.
To answer your second question, if you need to access your dynamically created controls, you can do so easily using their names, for instance:
Dim c As ClientesEmpresa= CType(Me.ClientesTabControl.TabPages("Tab1").Controls("Control1"), ClientesEmpresa)
c.CheckBoxProperty = True