I want to stop flickering of my form when VBA code is executed, but Application Echo is not working.
I have this code in Combobox_After_Update event :
Private Sub Combo11_AfterUpdate()
'Stop flickering
Application.Echo False
On Error Resume Next
'If User deletes Combo Item, then delete record
If IsNull(Combo11) Then
DoCmd.SetWarnings False
DoCmd.RunCommand acCmdDeleteRecord
End If
'Call code for re-positioning controls on form
Call MovingAllControls
'Close and reopen form
Call ReOpen
Application.Echo True
End Sub
Called procedure (which is probably cause of flickering):
Sub MovingAllControls
'Refresh
DoCmd.Requery
Const MaxRecs As Integer = 10
Dim NumRecs As Integer
On Error Resume Next
'find last record in subform and then expand Detail section according to number 'of records
With Forms![MyForm]![MySubform].Form
.Recordset.MoveLast
NumRecs = .RecordsetClone.RecordCount
If NumRecs > MaxRecs Then NumRecs = MaxRecs
.InsideHeight = NumRecs * .Section(0).Height + 350
End With
'Moving all controls under subform - in this example only one, but in reality I 'have plenty controls to move on form
Forms![MyForm]![FieldName].Top = Forms![MyForm]![Myubform].Top + Forms![MyForm]![MySubform].Form.InsideHeight + 1100
End Sub
Another procedure that is called from Combobox_After_Update event:
Sub ReOpen()
'I reopen form, because this is only way my subform controls moves as they 'should - dynamically
DoCmd.Close acForm, "MyForm"
DoCmd.OpenForm "MyForm"
End Sub
I also tried to to see what error is producing in After_Update_event, and I get error "424 - object required", but my code excecutes, only problem is flickering of controls. Any other way to stop flickering, or what is wrong with my code ?
Thanks for help !!
Rather than Application.Echo False, try the Form.Painting method:
' code under form
Me.Painting = False
' do actions that cause flicker
Me.Painting = True
Me.Repaint
Also, looking at your code here:
DoCmd.Close acForm, "MyForm"
DoCmd.OpenForm "MyForm"
I would say this is bad practice:
This can cause performance problems for even moderately large record sets.
If you use events like Form_Open or Form_Close, this can cause bugs by re-running code that was intended to only run once, when the form was first opened.
There is always a way in Access to get the results you want without closing/reopening the form.
Related
I would like to web scraping all the job title and company name from a job search website. However I unable to do so as I believe I cant inspect the correct element in the HTML codes. I researched this for days, please assist and advise on the correct HTML element. Once I able to inspect the correct element and I will do the looping and finish this program. Appreciate.
Website: https://www.efinancialcareers.my/search/?countryCode=MY&radius=40&radiusUnit=km&page=1&pageSize=20¤cyCode=MYR&language=en0
Option Explicit
Sub xmlhttp_scraping()
Dim XMLrequest As New MSXML2.XMLHTTP60
XMLrequest.Open "GET", "https://www.efinancialcareers.my/search/?countryCode=MY&radius=40&radiusUnit=km&page=1&pageSize=20¤cyCode=MYR&language=en0", False
XMLrequest.send
Dim iDOC As New MSHTML.HTMLDocument
iDOC.body.innerHTML = XMLrequest.responseText
'Cells(2, 2).Value = iDOC.getElementsByClassName("d-flex justify-content-between")(0).getElementsByTagName("h5")(0).getElementsByTagName("a")(0).innerText
'Cells(2, 2).Value = iDOC.getElementById("8091724").innerText
'Cells(2, 2).Value = iDOC.getElementsByClassName("search-card")(0).getElementsByClassName("d-flex justify-content-between")(0).getElementsByTagName("h5")(0).getElementsByTagName("a")(0).innerText
Range("H1").Value = "Time Updated on"
Range("I1").Value = Now
Columns.AutoFit
MsgBox "Done"
End Sub
Sample of HTML code below:
The page you try to get creates the contents using JavaScript. However, in your code, innerHTML of iDOC is only static content.
For the page to property run JavaScript, you can automate IE using InternetExplorer.Application. Try googling keywords like "Automate Internet Explorer Using VBA."
EDIT
I read your comment. The page gets the READY state too quickly. So, you should wait for the contents to be generated in some way (e.g. sleep or check some element appeared).
Public Declare Sub Sleep Lib "kernel32" (ByVal ms As Long)
Sub sc2()
Dim objIE As New InternetExplorer
objIE.Visible = True
objIE.navigate "https://www.efinancialcareers.my/search/?countryCode=MY&radius=40&radiusUnit=km&page=1&pageSize=20¤cyCode=MYR&language=en0"
Do While objIE.Busy = True Or objIE.readyState < READYSTATE_COMPLETE
DoEvents
Loop
Dim htmlDoc As HTMLDocument
' Wait long enough
Sleep 10000
' ... Or wait until some element appears (some element disappears)
' Do
' Set htmlDoc = objIE.document
'
' If htmlDoc.getElementsXXX Then
' Exit Do
' End If
'
' DoEvents
' Sleep 1000
' Loop
Set htmlDoc = objIE.document
' Then you can access elements
' ... but this code also has a problem. ``.getElementsByTagName("h5")`` returns nothing. Please inspect the html.
Debug.Print htmlDoc.getElementsByClassName("d-flex justify-content-between")(0).getElementsByTagName("h5")(0).getElementsByTagName("a")(0).innerText
End Sub
Moreover, the code that accesses the elements also has a problem. Since it doesn't follow generated html, .getElementsByTagName("h5") returns nothing. Please inspect the html in Chrome's console or VBE's Watch window.
== $0 is not related to your problem. It simply means the active DOM element in the developer tool. (What does == $0 mean in the DOM view in developer tools?)
By the way, more and more sites are dropping support for IE. Using InternetExplorer object is convenient, but automating Chrome or Firefox with Selenium is a better approach.
I have some inconsistent behaviour with a drop down list.
When it postback and the selected index is 1, it goes through and works as it should, gets the data, builds the UI, and writes everything to the screen.
if the selected index is 2 then it goes through the BuildUI() method, and then goes through the loop again thinking that the selected index is 0 and then doesn't build the UI.
this is the code
Protected Sub Page_Complete() Handles Me.LoadComplete
If _IsAuth = True Then
'if user is authorised to use the application, and the drop down menu has UK or GE
'selected then the the UI will be build for the user.
If Page.IsPostBack And ddlCharterVersion.SelectedIndex > 0 Then
BuildUI()
'once the UI has been built the dropdown list is to be hidden
ScriptManager.RegisterStartupScript(Me, GetType(Page), "ddlCharterVersion", "$('#paymentType').hide();", True)
Else
'if the user is not authorised they are passed a message showing that they are not authorised from the master
'page and the panel holding the divs and information will be hidden
ScriptManager.RegisterStartupScript(Me, GetType(Page), "hidePayments", "$('#panelHead').hide();", True)
End If
End If
End Sub
Protected Sub ddlCharterVersion_SelectedIndexChanged(sender As Object, e As EventArgs) Handles ddlCharterVersion.SelectedIndexChanged
ddlCharterVersion.Enabled = False
End Sub
And this is the dropdown on the page.
<div class="col-md-10 pull-left "><asp:dropdownlist runat="server" width="200px" id="ddlCharterVersion" AutoPostBack="True">
<asp:ListItem Value="-- Select Charter Version -- ">-- Select Charter Version -- </asp:ListItem>
<asp:ListItem Value="UK">UK</asp:ListItem>
<asp:ListItem Value="GE">GE</asp:ListItem>
</asp:dropdownlist></div>
When debugging the application I don't hit any errors that should cause the page to postback.
what puzzles me the most is that selected index position 1 works fine, position 2 does not.
If anyone can see directly what the issue is I would be very grateful for your assistance.
--update--
-- update 2 --
when debugging this, I never hit any of the exceptions, and have a breakpoint on each of them and none of them are ever hit.
Protected Sub BuildUI()
'gets the next record for payment
GetNextRecordForPayment()
If noRecords = False Then
'if there are records, concatenate the list of payments into one row in a list
ConcatenateListOfPayments()
''write the records to the UI
writeRecordsToUI()
End If
End Sub
Protected Sub GetNextRecordForPayment()
Try
''if a user already has a record locked and has refreshed the page for any reason
''get this record back until they pass it to the excptions queue or validate for payment
'UserHasRecordLocked is returned as an object. Either as the contactId of the locked record or False
Dim UserHasRecordLocked = CheckForLockedRecord()
Dim lockedRecord As Long
Dim contactIdParam As New SqlParameter("#LockedRecord", SqlDbType.BigInt)
Dim charterVersionParam As New SqlParameter("#CharterVersion", SqlDbType.VarChar)
charterVersionParam.Value = ddlCharterVersion.SelectedValue
'check the type of object of UserHasRecordLocked
If UserHasRecordLocked.GetType = GetType(Long) Then
'if it has a record then assign the value of UserHasRecordLocked
'to the sqll parameter.
contactIdParam.Value = UserHasRecordLocked
Else
'else give it a default value
contactIdParam.Value = 99999
End If
'place all parameters into a list object of sql parameter
'this has been done this way so that you dont have to be
'precious or careful of where you place your parametss
Dim listOfParam As New List(Of SqlParameter)
listOfParam.Add(contactIdParam)
listOfParam.Add(charterVersionParam)
''gets all records due to be paid
Dim dt As DataTable
'get the first payment \ contact back in a datatable.
'brings back all the parts of the payment, ie redress, d&i, hmrc deductions
'and later concatenates them into one line
dt = DataAccessLayer.FindRecords(listOfParam, _charterPayments, "dbo.usp_getFirstRecordForPayment")
If dt.Rows.Count = 0 Then
noRecords = True
'if there are no records inform the user that there are no payments to be made this day.
ScriptManager.RegisterStartupScript(Me, GetType(Page), "noPayments", "$('#noPayments').modal();", True)
Exit Sub
End If
'build a list of payments using a payee class
BuildListOfPayments(dt)
'using MoreLINQ to get the First or Default record to get the most basic of information out.
Dim paymentInfo = listOfPayments.FirstOrDefault()
''if payment is an IVA, C&R or Deceased Case this will be thrown to the exceptions for manual handling.
If paymentInfo.isException = True Then
'record the exceptions
Dim recorded = RecordNewException(paymentInfo.ContactId, paymentInfo.ContactPartId, paymentInfo.ExceptionReason, True)
If recorded = True Then
'post the page back to get the next record and start the loop again
Response.Redirect(Request.RawUrl, False)
Context.ApplicationInstance.CompleteRequest()
End If
End If
Try
'set the class level variable
_PaymentCategory = paymentInfo.Category
Catch ex As Exception
Dim recorded = RecordNewException(paymentInfo.ContactId, paymentInfo.ContactPartId, "Cannot match complaint against a category type", True)
If recorded = False Then
Response.Redirect(Request.RawUrl, False)
Context.ApplicationInstance.CompleteRequest()
End If
End Try
'lock the record so that no other user can be working on this at the same time
LockRecord(dt)
If paymentInfo.charterVersion = "GE" Then
'if the payment is coming from GE Charter then complete various checks
checkGeCharterPayments(paymentInfo)
ElseIf paymentInfo.charterVersion = "SANUK" Then
'if the payment is coming from GE Charter then complete various checks
checkSanCharterPayments(paymentInfo)
Else
Exit Sub
End If
Catch sqlEx As SqlException
PassToErrorHandler(sqlEx, System.Reflection.MethodInfo.GetCurrentMethod().ToString(), System.Reflection.Assembly.GetExecutingAssembly().GetName().Name)
Catch ex As Exception
PassToErrorHandler(ex, System.Reflection.MethodInfo.GetCurrentMethod().ToString(), System.Reflection.Assembly.GetExecutingAssembly().GetName().Name)
End Try
End Sub
I had a situation where I was dynamically creating LinkButtons basically with no properties set on PageInit, and then later on adding the properties about those LinkButtons on another separate button's click event.(i.e. text, adding a click eventhandler, etc).
The problem was, I had to click the LinkButton twice for the click event handler to fire. Bear in mind, all of this is inside an update panel.
After looking at it up and down, I realized I was setting the ID for it to the same thing twice (on PageInit and also when I later set the properties). I saw that and figured it would muck up things in the control hierarchy and I understand it was the problem...but what I don't fully understand is the why.
Can someone explain to me what the technical cause was for having to click the LinkButton twice and why setting the ID to same thing twice caused this?
CODE
This occurs on CreateChildControls()
Private Sub InitializeLinkBreadCrumbPlaceHolders()
Dim counter As Integer = 0
'Adding the handlers has to take place before/on Page.Init...
For counter = 0 To LEVEL_CAP
_linkDynamic = New LinkButton()
'Add all the links
Me._placeHolder.Controls.Add(_linkDynamic)
With _linkDynamic
AddHandler .Click, AddressOf Link_Click
.Style.Add("display", "none")
.ID = String.Format("lbl{0}", counter)
End With
Next
End Sub
And this occurs when a regular button is pressed (keep in mind all of this is inside an update panel)
Private Sub SetHyperLinkBreadCrumbValues(Optional ByVal ShouldAddAsLink As Boolean = True)
'Don't add a new link if we went backwards
If ShouldAddAsLink Then
Me.Links(Me.CurrentLevel) = Me.LinkHeader
End If
'Go through the collection to set the values of the existing linkbuttons
For Each element As DictionaryEntry In Me.Links
'Links 1-based index
With CType(Me._placeHolder.Controls.Item(CInt(element.Key) - 1), LinkButton)
.Font.Name = "Arial"
.Font.Size = 11
If CInt(element.Key) > 1 Then
.Text = String.Format(" > {0}", CStr(element.Value))
Else
.Text = CStr(element.Value)
End If
.Visible = True
.Style.Add("display", "inline")
End With
Me.TrimDescriptionLink(CType(Me._placeHolder.Controls.Item(CInt(element.Key) - 1), LinkButton))
Next
End Sub
I have seen (and even caused) this behavior from time to time. Inevitably you are not always adding the control (or wiring up the OnClick event in PageInit. The first click causes a PostBack and on the second server page life cycle, you add the control during PageInit. On that second time around (and second button click), the event is wired up and fires the correct event. Are you possibly not wiring up the OnClick event every time during PageInit ?
Can you share some code?
currently I am working on a project named online exam.
All the controls are dynamically created.
I have a webpage where I want to display the student details.
I displayed those details correctly in a table.
Now here comes the time to edit those details.
To edit a record I use the linked button named edit.
When a user clicks on that Linked button the data in that row is replaced with new textboxes.
Upto here I am OK.
Now when I click on the save changes button after making changes to the textboxes.
The old values are not replaced by the new values and the old values remains.
The code for creating textboxes in the table is as follows :
Public Sub Edit_Click(ByVal sender As Object, ByVal e As System.EventArgs)
For x As Integer = 0 To EditList.Count - 1
If sender.id.substring(4) = EditList(x).ID.Substring(4) Then
Session("PreviousRollNo") = RollNoList(x).Text
Dim txtName As New TextBox
txtName.Text = NameList(x).Text
NameList(x).Text = ""
NameList(x).Parent.Controls.Add(txtName)
txtList.Add(txtName)
Dim txtCourse As New TextBox
txtCourse.Text = CourseList(x).Text
CourseList(x).Text = ""
CourseList(x).Parent.Controls.Add(txtCourse)
txtList.Add(txtCourse)
Dim txtAdmissionDate As New TextBox
txtAdmissionDate.Text = AdmissionList(x).Text
AdmissionList(x).Text = ""
AdmissionList(x).Parent.Controls.Add(txtAdmissionDate)
txtList.Add(txtAdmissionDate)
Dim btnSaveChanges As New Button
btnSaveChanges.Text = "Save Changes"
EditList(x).Text = ""
EditList(x).Parent.Controls.Add(btnSaveChanges)
AddHandler btnSaveChanges.Click, AddressOf btnSaveChanges_Click
Session("EditButtonClicked") = True
Dim btnCancel As New Button
btnCancel.Text = "Cancel"
DeleteList(x).Text = ""
DeleteList(x).Parent.Controls.Add(btnCancel)
AddHandler btnCancel.Click, AddressOf btnCancel_Click
Session("CancelButtonClicked") = True
txtName.Focus()
Exit For
End If
Next
End Sub
The code for Save Changes button is as follows :
Public Sub btnSaveChanges_Click(ByVal sender As Object, ByVal e As System.EventArgs)
If txtList(0).Text = "" Then
Dim trError As TableRow = New TableRow
Dim tdError As TableCell = New TableCell
tdError.ColumnSpan = 7
Dim lblError As New Label
lblError.Text = "Please enter name of the student."
lblError.ForeColor = Drawing.Color.Red
tdError.Controls.Add(lblError)
trError.Controls.Add(tdError)
tbl.Controls.Add(trError)
ElseIf txtList(1).Text = "" Then
Dim trError As TableRow = New TableRow
Dim tdError As TableCell = New TableCell
tdError.ColumnSpan = 7
Dim lblError As New Label
lblError.Text = "Please enter the course."
lblError.ForeColor = Drawing.Color.Red
tdError.Controls.Add(lblError)
trError.Controls.Add(tdError)
tbl.Controls.Add(trError)
ElseIf txtList(2).Text = "" Then
Dim trError As TableRow = New TableRow
Dim tdError As TableCell = New TableCell
tdError.ColumnSpan = 7
Dim lblError As New Label
lblError.Text = "Please enter the Admission Date"
lblError.ForeColor = Drawing.Color.Red
tdError.Controls.Add(lblError)
trError.Controls.Add(tdError)
tbl.Controls.Add(trError)
Else
Dim cb As New OleDbCommandBuilder(da)
Dim editRow() As DataRow
editRow = ds.Tables("Student_Detail").Select("Roll_No = '" & Session("PreviousRollNo") & "'")
editRow(0)("Name") = txtList(0).Text
editRow(0)("Course") = txtList(1).Text
editRow(0)("Admission_Date") = txtList(2).Text
da.Update(ds, "Student_Detail")
Page.Response.Redirect("ChangeUserDetails.aspx")
End If
End Sub
I get the error sying that array is out of the bounds. on the first line of the btnSaveChanges_Click.
It means txtlist is always cleared when I click on Save Changes Button.
So I stored txtList in a Session like Session("txtList") = txtList.
and retrieved the data from that. But now I get the old values of the textbox instead of the newer ones.
Here txtList is a list (of Textbox)
Firstly, welcome to the ASP.NET WebForms Page Life Cycle. Remember its pattern with the simple mnemonic: SILVER = Start, Init, Load, Validate, Events, Render.
Secondly, HTTP is stateless. WebForms does an amazing job of hiding this fact from you using ViewState until you do something a little out of the ordinary (as you're now attempting), and it all appears to fall apart. What's really happening is that you're starting to see side-effects of how WebForms is managed, and how it's not as much like WinForms (or another stateful system) as you might think.
When you're responding to an event server-side in WebForms, it's easy to get the impression that nothing has changed. That the entire page is as you left it "last time". All the controls are there, the values you may have set programatically are still set. Magic. Not magic. What's actually happened is the entire page has been re-constructed to respond to that event. How was it re-constructed? By a combination of your page definition (markup), actions taken in control event handlers, and the form data posted back by the client.
Confusing? OK, let's consider an example. Say you've got a page with two controls on it. A textbox named txtInput and a button named btnSubmit with event handler btnSubmit_Click. When the user first requests the page, the HTML for these controls is derived from your markup (aspx page) and returned to the client. Next, the user sets a value in txtInput and clicks the submit button. The server then re-creates the page from scratch based on your markup. At this early stage of the life-cycle, the controls still have their default values. We then hit the Load stage of the life-cycle, and "if the current request is a postback, control properties are loaded with information recovered from view state and control state." In other words, by the time the life-cycle gets to Init, the control has been created from markup, but still has its default value. The Load stage then sets the value according to Postback data.
Left wondering how this applies to your scenario? You're adding your dynamic controls in response to a control event. There's two things wrong with that:
It's too late in the page life-cycle for Init to set the values based on data posted back from the client (recall SILVER, Event is after Init).
Your button click event handler is only run once, in response to the postback where the user clicked the button. But remember on each postback the page is entirely re-created. So the dynamic controls no longer exist as far as the server is concerned! You'll notice that not only are the controls not present server side when responding to the submit event, but after the page has handled it, they're no longer present client-side either.
So what's the answer? Well the "Life-Cycle Events" section of the page I linked offers a clue. It states that the PreInit event be used to (among other things) "Create or re-create dynamic controls". Why would we do it in PreInit? So it's early enough in the page life-cycle for the later events to properly handle it (like setting the values posted back from the client).
Now, I know, you want to add the controls based on the user clicking on the button. How does that fit? The trick is that you've got to manage the "state" yourself. Huh? the state? By this I mean MyDynamicControlsShouldBeShown = true / false. When the button is clicked, creating the controls in response to the button-click event handler is the right action (there's not really any choice there). But you need to store that state somehow so you know on subsequent requests to the page, whether those controls should be re-created in PreInit. One neat option would be to check for the ID of your dynamic control in Request.Form.Keys. If the control ID is present in the Keys collection, then the user is posting back a value for the control, so you should re-create it.
A side-note on the use of Session
Hopefully based on the above you've realised why putting the controls into Session didn't work. But to be clear, the controls you put into the Session object were no longer part of a page that existed (remember, the page gets completely re-created for each request. Those controls were no longer hooked up to the Page events, so didn't get their values populated between Page Init and Load. If somehow it did work, it still wouldn't be a particularly good idea, as Session is not per-request. So what would happen if a user had the same page open in multiple tabs? Strange things, that's what.
I'm sure this question has been asked a million times, however I haven't been able to find an answer that solves my problem.
I am programmatically adding some custom user controls to a PlaceHolder which I have on a simple aspx page. All of the user controls Postback's work correctly except for one which has a Gridview on it.
For some reason any postback that gets fired from within this control, does not call the specified event on the first click, however all future clicks it will work fine. I have no idea why this is the case, but many solutions I have found, suggest adding an ID to the ascx User Control, however this doesn't work in my case.
I've taken a look at the source file for the page that gets generated before and after the first click, javascript used for calling the postback changes, i.e
Before first click: onclick="javascript:__doPostBack('tmpControlID$sgvPrimaryEmploymentHistory','Select$0')"
After first click: onclick="javascript:__doPostBack('OFFHome1$tmpControlID$sgvPrimaryEmploymentHistory','Select$0')"
OFFHome1 is the parent user control which exists on the aspx page. All other controls are added to a placeholder in this control, i.e.
<%# Control Language="vb" AutoEventWireup="false" CodeBehind="OFFHome.ascx.vb" Inherits="UmbracoUserControls.OFFHome" %>
<asp:PlaceHolder ID="phOFFSection" runat="server"></asp:PlaceHolder>
Nothing to complicated. Then in the code behind the controls are loaded into the placeholder using the following:
Private Sub LoadNextOFFStep()
Dim ControlName As String = "TestControl.ascx"
phOFFSection.Controls.Clear()
If ControlName IsNot Nothing AndAlso ControlName <> String.Empty Then
Dim NewControl As Object = LoadControl(ControlName)
With NewControl
.ID = USERCONTROLNAME
Dim StepCompleted As Boolean = .FillControl()
If StepCompleted Then
Exit Sub
End If
Dim AllowSkip As Boolean = .AllowSkip()
btnSkip.Visible = AllowSkip
End With
phOFFSection.Controls.Add(NewControl)
End If
End Sub
Again, nothing overly complicated. The USERCONTROLNAME is just a const with the value "tmpControlID" in it.
The control that is giving me trouble is a little complicated, I was originally using a custom GridView control that we have created, but have removed it and replaced it with the standard asp one to see if the problem still occurs, and it does.
Any button, on control which fires off a postback will fail the first time, and all future click will work correctly. On the first click the Page_Load event will get called, but that is it.
What am I doing wrong??
After far too much time spent on this, I have finally worked it out.
It was to do with the order of events, however just not where I had thought. The FillControl function was getting called before User Control had been added to the PlaceHolder. I changed this so that it gets called after the User Control was added to the PlaceHolder and now it works first time.
Basically the code looks like this now:
Private Sub LoadNextOFFStep()
Dim ControlName As String = "TestControl.ascx"
phOFFSection.Controls.Clear()
If ControlName IsNot Nothing AndAlso ControlName <> String.Empty Then
Dim NewControl As Object = LoadControl(ControlName)
With NewControl
.ID = USERCONTROLNAME
Dim AllowSkip As Boolean = .AllowSkip()
btnSkip.Visible = AllowSkip
End With
phOFFSection.Controls.Add(NewControl)
Dim StepCompleted As Boolean = CType(phOFFSection.Controls(0), Object).FillControl()
If StepCompleted Then
LoadNextOFFStep()
Exit Sub
End If
End If
End Sub
Thanks for everyone's help.
Well... the answer to the first question is simple: It fails the first time because the ID of the control (or rather, in the postback script) is different on subsequent page loads. It works on subsequent clicks because the control ID stays the same.
Now as to WHY that is... much tougher! But probably something to do with the order of operations here.
Try explicitly setting the NamingContainer value for NewControl:
With NewControl
.NamingContainer = OffHomeOne; // whatever
.ID = USERCONTROLNAME