Extension method does not respect My.Application.Culture - vb.net

In a VB.NET 4.72 WinForms project, i have placed an MDI form (MDIForm1), an MDIChild form (Form1) and a module. In the module, i have declared an extension method:
<Extension()>
Public Sub ShowChild(SourceForm As Form)
MessageBox.Show(My.Application.Culture.ToString)
End Sub
In the MDIForm's Load event, i have the following code:
My.Application.ChangeCulture(NewCultureName)
My.Application.ChangeUICulture(NewCultureName)
'NewCultureName is a string which is set to any valid value other than "en-US".
Form1.ShowChild
When debugging the project, the MessageBox that appears when ShowChild is called, displays "en-US" instead of the value of NewCultureName. If a breakpoint is placed in "Form1.ShowChild" statement, i can see that the culture has indeed changed to the value of NewCultureName. The application acts though as if there are two different instances of My.Application, one in the MDI form and another inside ShowChild. Why is this happening?
2019-04-14: Edited to a more precise description of the issue.

Related

Me.controls.Item on a VB.net Form is returning System.nullReferenceException 'object reference not set...'

I've created a vb net form that uses an array list to load data into various controls. (ultimately this is to interface with the Autodesk Inventor API, but I'm not failing the API part)
My first form(1) works correctly. I needed to break my form into multiple forms due to too much information. In Visual Studio 2022 I copied my Form1, pasted it and renamed it to Form2 then changed the references to Form1 located in Form2.designer.vb. To switch between Forms, I created a 'MainMenu' form to call either Form1 or Form2
By all manner of double checking, my method of calling my Form1 or Form2 are a copy paste (other than form names)
On my new form2, I cannot access any controls using the Me.Controls.Item method. I use a button to run the population of my textbox controls, so they exist.
works:
Me.textbox1.text = "some string"
Me.text = "form name string"
doesn't work:
Me.Controls.Item("textbox1").text = "any string"
In debug, mousing over the error line I get:
Me = {Projectname.Form1...} Me.Controls = {System.Windows.Forms.Form.ControlCollection} Me.Controls.Item("textbox1") = Nothing
In the Autos window, I can see my textbox1 in Me.Controls > Owner > textbox1 (and my 'some string' value)
I can also see my control in the Locals Me > textbox1
I guess I did something wrong when Copy/Pasting my Form1 to Form2
I created a new Form3 and copy pasted the controls and the Code from my Form2 and I have the same issue.
I have crated a new Form4 and created a new control (textbox) without a copy paste and things seem to work on that form, so far.
I'm sure somebody could fix this in seconds, but I'm tapped out. My Form2 (i could have sworn it worked before) has a lot of time into formatting multiple layers of tablelayoutpanels and would really like to not re-create my form2 from scratch.
If Me.Controls.Item("textbox1") is Nothing then there is no control whose Name property is "textbox1" and whose direct Parent is the form. As you can see, there are two conditions that could cause that to be the case. The control you want does not have its Name property set to "textbox1" and/or its direct Parent is some other control, e.g. a Panel.
Personally, I would scrap that form and create a new one the conventional way. Obviously you have done something wrong so who knows how far-reaching the issue(s) is?

How to use Form Controls in Modules

In my modules, I want to use my controls from my form. For example: I want to set focus on a textbox after a certain Sub.
My current solution is to make a subroutine to set all controls in a public variable (see below).
My questions:
What is the best practice? How do people usually do this?
When should I call my subroutine? (is it the first call in the FORM_LOAD sub?)
Public TBnr As TextBox
Public Sub controlsInitieren()
Set TBnr = Forms("frm_TreeView_Example").pstNr
End Sub
Well, as a general rule, while many platforms seperate out the UI part and the code part? Well, Access is quite much a different approach - it is standard fair to place the required code inside of the form "class" (all forms in Access are a "class", and you can even have muliple instances of the SAME form open more then one time).
So, in general, your code should be in the forms code (class) module.
However, you could and call a external routine.
So in the form, you could call your above routine like this:
Call MySetFocus(me, "NameOfControlToSetFocusTo")
And your sub would look like this:
Sub MySetFocus(f as form, sCtrl as string)
f(sCtrl).SetFocus
End Sub
However, as noted, the amount of code above is more code then simply in the forms code module going:
me.ControlName.SetFocus
However, while the above is a less then ideal example, passing the form "instance" (me) to a external sub or function allows you to referance any property or method or feature that exists in the form in an external routine.
So in place of say
me("LastName") = "Zoo"
In the above sample routine, you would and could go;
f("LastName") = "Zoo"
So any place you would and could use "me" in the form, you can use the form instance you passed from the form. As noted, it is a good idea to use "me", since as I noted, Access does allow multiple copies of the form to be opened at the same time - and thus your code can't distinguish between what form instance you are using unless you pass the current "in context" form. So like in JavaScript, using "this" ?
In access that current instance of the class object is "me", and you are free to pass that instance to any sub or function you want as per above.
The best practice is to use only procedures inside the form code. In such a case you refer to a text box control in this way: Me.Textbox1.SetFocus. If you want to set some controls properties during the form loading, you can do that in the frm_TreeView_Example_Initialize event;
They usually do it in the way I described at item 1;
If you want to use such a strange/unusual way you can do it calling the subroutine whenever you want. But, in order to set a specific property value of the form frm_TreeView_Example controls you can simply use frm_TreeView_Example.TextBox1.SetFocus. You can use this way of setting in a module procedure, even before the form has been shown. You can simply show it in that procedure code using at the end: frm_TreeView_Example.Show;

pass control values window forms

I have a form with 5 controls.
For textbox I am accesing like frmNote.txtNumber.Text.
When I am accessing this property directly from form frmNote then I am getting the value of textbox.
But when I created a method for example NewMethod() in different vb file and call this method from frmNote form button click event then I am not able to access frmNote.txtNumber.Text value over there inside method.
It is coming blank. Do I need to pass all control values to method from form or is there any other way around.
Because txtNumber isn't shared, you can't access it from other class. You must pass it's value to NewMethod. Code will look like this:
Public Sub NewMethod(text as String)
'Use text
End Sub
And calling NewMethod:
NewMethod(txtNumber.Text)

How to reference a subform in MS Access

In my MS Access application, I am using a form which contains only two controls - a textbox and a command button. This form is named as HEADER FORM.
HEADER FORM is used as a subform in header section of various other forms.
What I want to do is that whenever a particular form loads, I want to fill details in the textbox of the HEADER FORM (that will be name of the person who has logged in. The same would be clear from the picture below).
I am trying to call a global subroutine named updateHeader in form load event of all the forms.
Public Sub updateHeader()
Me![HEADER FORM].Form.txtHeaderName.Value = strPerson
End Sub
Following is the picture showing HEADER FORM in Design View and the same being used as a subform in a login form.
I tried various other options but am not able to come out with the correct way to reference the form. Am I doing something wrong fundamentally?
The error that I am seeing is invalid use of Me keyword.
Also, my updateHeader subroutine is a global subroutin which is called from Form_Load event of all the forms.
If your updateHeader() procedure is contained in a standard module, that would explain the complaint about the Me keyword ... it's not valid in a standard module.
In a form module, Me means "this form".
You could change the procedure declaration to accept a reference to a form.
Public Sub updateHeader(ByRef TheForm As Form)
' Me![HEADER FORM].Form.txtHeaderName.Value = strPerson
TheForm![HEADER FORM].Form.txtHeaderName = strPerson
End Sub
.Value is the default property and therefore not needed here, so I left it out. But it won't hurt to add it back if you prefer.
You can then call the procedure from the parent form, and pass the procedure a reference to itself (the parent form).
updateHeader Me
I got these "syntax versions" from Wiley.Microsoft.Office.Access.2007.Bible:
When referencing subform controls:
Forms![FormName]![SubformName].Form![ControlName]
When using/referencing subforms within subforms, use the following syntax:
Forms![FormName]![SubformName].Form![SubSubformName].Form.[ControlName]

Reading 'Checked' Property Of Dynamic CheckBox on Page Postback

Apologies in advance for the long-winded post, but I'm having some trouble with a .NET page I'm building.
END QUESTION: How can I check the 'Checked' property of a dynamically-created checkbox during the Page_Load subroutine?
DETAILS: Basically, I have a VB.NET page that creates some table rows dynamically, based on a number selected by the user. So, for example, if the user selects "3" from a dropdown list, the page posts back and creates three table rows. Each row contains a couple of textboxes, a dropdown list, and a checkbox (which are all .NET form controls rather than plain HTML controls, I should point out).
Typically, the user would enter a few details into the form controls, and click the 'Submit' button, after which the page iterates through each row, and inserts the data into a SQL Server table.
But if the user ticks the checkbox for that row, this signifies that the page is to ignore that row, and NOT insert that row of data into the database when the user clicks 'Submit'.
This works well, but there is a problem. If the user clicks 'Submit' and some of the values entered into the form controls are invalid (so, for example, the user didn't enter their name) then the page won't submit the data, and instead, shows an error to the user informing them of the values they need to change. But if the user creates three rows, for example, but decides to "ignore" the third row (by ticking the checkbox) then when the page posts back, finds some invalid entries, and re-shows the form to the user to allow them to correct any errors, I'd rather the page didn't render the third row altogether. After all, they chose to create three rows originally, but then decided that they only needed two. So it makes sense that the third row is not recreated.
To start with, I simply used code similar to the following within my Page_Load subroutine:
If objCheckbox.Checked = False
' Render the row, and recreate the dynamic controls '
Else
' Dont render the row or any of the controls '
End If
But what seemed to happen was that objCheckbox.Checked was always returning False, even when the checkbox was ticked. Once the page had loaded, the table rows had rendered again, and the tick was present in the checkbox, so it's not like the value was lost on postback. But at the point I check whether the checkbox is ticked, it always returns False, rendering a table row that the user doesn't need.
Does anyone know how to get round this problem? I've read lots of articles about the .NET ViewState, and the page lifecycle, but I've yet to find a solution that works. I simply need to be able to check if a checkbox is ticked before re-creating some dynamic controls.
I tried this alternative code, which utilises the ViewState, but to no avail:
If objIgnoreCheckbox.ViewState("Checked") = False Then
' Render the row, and recreate the dynamic controls '
Else
' Dont render the row or any of the controls '
End If
When doing this, I get the following error:
'System.Web.UI.Control.Protected Overridable ReadOnly Property ViewState() As System.Web.UI.StateBag' is not accessible in this context because it is 'Protected'.
So I tried to create a custom class, that inherited from Checkbox, and tried to override the ViewState property to make it public, so that it can be read from:
Public Class CheckboxControl
' Inherits all Checkbox properties and methods '
Inherits Checkbox
' Create the public ViewState property '
Public Overrides ReadOnly Property ViewState As StateBag
Get
Dim objChecked As Object = ViewState("Checked")
If Not (IsNothing(objChecked)) Then
Return objChecked
End If
End Get
End Property
End Class
But then I basically found out that you can't override a protected member with a public one. I've had very little experience with creating new classes etc, so I'm stumped.
So if anyone can tell me how to go about checking the darned checkbox, I'd be eternally grateful! I've spent a full working day trying to solve the problem, but with no luck!
Thanks in advance!
For static controls, the view state of controls is restored in Page_Init, which happens before Page_Load, so they contain the correct values in Page_Load. Dynamic controls are created in Page_Load, so their viewstate is incorrect in Page_Load and will be restored after Page_Load, but before calling event handlers. MSDN says:
After the Page_Load event has run, but before control event-handling methods are called, the remaining view state information is loaded into the dynamically created controls.
This is why Checked returns false, and why changing the visibility of CheckBox.ViewState will not solve your problem.
Solution (untested, but I think it should work): Create all controls (even those that you don't want to display) in Page_Load. Attach an event handler on CheckedChanged to your CheckBoxes (in Page_Load). After Page_Load has finished, ASP.NET will restore the view state of the newly created controls (that's why it is important to create the same controls in Page_Load, so that ASP.NET can correctly map the view state to the control), and ASP.NET will call your event handler for those CheckBoxes that have been changed. There, you can remove the rows you don't want to display.
This is how you add the event handler
AddHandler objCheckbox.CheckedChanged, AddressOf MyCheckedChangedFunction
This function would look something like this:
Function MyCheckedChangedFunction(sender As Object, e As EventArgs)
Dim objCheckbox = DirectCast(sender, CheckBox)
... access objCheckbox.Changed and do something useful here ...
End Function