I have this dropdownlist, this one load with the data that I get from a store procedure, as you can see the load is correct, but when I change the selected value in the debug the selected value doesnt change, it stays in the first loaded value, which in this case is 1. What can I do?
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim adaptador As New SqlDataAdapter
Dim datos As New DataTable
Dim ord As SqlDataReader
Conexiones.AbrirConexion()
Conexiones.Cnn.Open()
Dim cmd As SqlCommand = New SqlCommand("sp_devolver_empresas", Conexiones.Cnn)
cmd.CommandType = CommandType.StoredProcedure
ord = cmd.ExecuteReader
datos.Load(ord)
cbEmpresas.DataSource = datos
cbEmpresas.DataTextField = "Nombre"
cbEmpresas.DataValueField = "Identificador"
cbEmpresas.DataBind()
Conexiones.Cnn.Close()
End Sub
For EVERY web page that you build and write to the end of time?
You MUST always put the load and setup code inside of a check for post back.
every button, every drop down list, and EVERY time you click on a button or do anything, the page load will ALWAYS fire and run. Thus if you change a value, you will lose that value since the page setup and loading of say control (in this case your dropdown list) will fire EACH time - thus overwriteing.
Out of the last 100's of web pages, the FIRST thing I write is the check for postback.
So, your code should look like this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadData
End If
End Sub
Sub LoadData()
Dim datos = New DataTable
Using onexiones.Cnn
Using cmd As SqlCommand = New SqlCommand("sp_devolver_empresas", onexiones.Cnn)
cmd.CommandType = CommandType.StoredProcedure
onexiones.Cnn.Open()
datos.Load(cmd.ExecuteReader())
End Using
End Using
cbEmpresas.DataTextField = "Nombre"
cbEmpresas.DataValueField = "Identificador"
cbEmpresas.DataSource = datos
cbEmpresas.DataBind()
End Sub
So, only on the "real" first page load do you want to load up your grids, dropdowns etc. Remember, even a simple button dropped on to the page, and you have a click event? (the page load event fires each time - and every time). So once again, you need the IsPostBack test - and I am quite pressed to find any of my web pages that does not have this all important code stub in the on-load event.
So, remember the above rule - always setup your setup code to run on first time - not every time a button or anything else occurs on the web page. So, page load (unlike desktop) fires each and every time you do ANY operations on that page.
Also, note how I setup the data text, and value field BEFORE we give the drop down list a data source. In fact, I would suggest you put the data text, and data value field in the markup and NOT code (since then multiple different code routines can use that setting - not hard coded in code).
eg do this:
<asp:DropDownList ID="cbEmpresas" runat="server"
DataTextField = "Nombre"
DataValueField = "Identificador" >
</asp:DropDownList>
So, now your code becomes :
cbEmpresas.DataSource = datos
cbEmpresas.DataBind()
I suppsoe some out of habt like to set the text + data settings for the dropdown list in code, but then again, in code you might want more then one palce that loads up the combo box - and thus you now have multiple places for those two settings. And better yet, you can even use the property sheet during design time to make the settings. (this is a "minor" issue, but I just perfer those settings in the markup as opposed to writing them in code for text/data settings).
At the end of the day? Just remember that golden rule: have that "test" for postback so you have a REAL first page load event code inside that if/then. In fact, you really can't even build a fnctional working web page if you break this rule. As noted, I count about 1-2 of my web pages out of 100's tht don't have that not postback code stub. It is quite much as important say compared to humans having to breathe air to function.
And why such a long post about this simple issue? Well on a near daily bases, both c# and vb.net questions are posted about how some combo box, grid view or just about anything else is "broken" and not working. And the answer 9 out of 10 times?
The developer forgot to use a Not IsPostBack code stub in their page load code.
If I was teaching asp.net, this would be the first lesson - ALWAYS use and consider the requirement for the Not IsPost back stub. You need that in 99% of your web pages. Or at the very least in ANY web page in which you have code to run on page load to setup grids, dropdowns, repeaters - don't matter what, you will NEED that code stub. So important, I often wonder if they should have create a even called first page load? It would have eliminated the daily posts and questions on SO that fail as a result of not heeding the above simple advice.
Edit: Now how to get selected value in code
Ok, now that we fixed up the code to setup the dropdown list, we now want to get in our code the value when the user makes a choice in the dropdown list.
You of course have code to fill the dropdown, BUT we also have to set autopostback = true for this dropdown.
So, say code to load:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
LoadData
End If
End Sub
Sub LoadData()
Using conn As New SqlConnection(My.Settings.TEST4)
Dim strSQL As String =
"SELECT ID, HotelName from tblHotels ORDER BY HotelName"
Using cmdSQL As SqlCommand = New SqlCommand(strSQL, conn)
conn.Open()
Dim rstData As New DataTable
rstData.Load(cmdSQL.ExecuteReader)
cboHotels.DataSource = rstData
cboHotels.DataBind()
End Using
End Using
End Sub
And now the selected index changed event:
so, our debug output would then look like:
output:
combo selected value = 82
combo selected Text = Canadian Rocky Mountain Resorts
And as noted, make sure you set auto-post back true in the property sheet, or in the markup. The combo box for above in markup thus is this:
<asp:DropDownList ID="cboHotels" runat="server"
DataValueField="ID"
DataTextField="HotelName" AutoPostBack="True">
</asp:DropDownList>
Related
Label is not visible in the following code . I need to show a message please wait when the user clicks login.It shows before but after adding the time interval its not showing
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Label3.Visible = True
If TextBox1.Text = "Akilan" And TextBox2.Text = "123" Then
System.Threading.Thread.Sleep(5000)
Form2.Show()
Hide()
Else
MsgBox("Sorry, The Username or Password was incorrect.", MsgBoxStyle.Critical, "Information")
End If
End Sub
Thread.Sleep on the UI thread will cause your form to "freeze". It sounds like you want some sort of waiting indicator while the background code is running.
What you should do is execute your long running code asynchronously, show your label, wait for the asynchronous code to finish, then do something (e.g. hide the label).
Using your code, it'd look something like this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Label3.Show()
If (TextBox1.Text = "Akilan" AndAlso TextBox2.Text = "123") Then
Dim t = Task.Run(Sub() Threading.Thread.Sleep(5000))
t.Wait()
Label3.Hide()
Else
MessageBox.Show("Sorry, the username or password was incorrect", "Invalid Credentials", MessageBoxButtons.OK, MessageBoxIcon.Information)
End If
End Sub
The way to do this is to hide/show the label text client side. Then when the page travels up to server and your code behind runs, the client side will still show that message. When you code behind is done, then the whole page now travels back down to the client side is re-load + re-display.
Grasping the above so called "round trip" is REALLY important here.
Since your code behind never interacts with the user, but only that copy of the web page that JUST traveled up to the server, and the code behind can play with, change and modif that page - but client side can ONLY see such updates AFTER the page travels all the way back down to client side. That's why this code can't work:
Label3.Visible = True
If TextBox1.Text = "Akilan" And TextBox2.Text = "123" Then
System.Threading.Thread.Sleep(5000)
Form2.Show()
Hide()
The above code will set Label.visible = true, but the whole page has not yet done its code, and the whole page is still on the server side. ONLY AFTER all your code is done, does the page travel back to client side, and show the label - but ALL code has to complete before page travels back down to client side.
However, this code will work just fine:
So lets look at above:
First up, we do NOT use visible=false for the label. The reason is that if you do that, then the label is NOT rendering in the markup.
Next up, we added a onclient click event to the button.
And we have our button code that has this code:
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Thread.Sleep(3000)
End Sub
So, when you run this, you see this for 3 seconds:
So what happens?
Well, you click on button - the OnClient code (javascrt client side) will run and THEN the post back of the page up to the server occurs.
So, since that label is now "show", then it will display. Now the web page is up on the server - your code behind runs. When code behind is done?
The WHOLE page now makes the trip back to browser client side. And this ALSO means our label message will automatic hide again - since the page is re-plotted with the whole new page that the server just send back to the client side.
Do note, that in above, I assumed jQuery is installed. If not then your script will have to be this:
function ShowLabel()
{
lbl = document.getElementById("lblMessage")
lbl.style.display = "inline"
}
Note also close how I set the id mode of lable = static - I often do that, since then referencing controls in js becomes a lot easier.
So, the real trick here?
We display the label client side, and then whatever and how ever long the server takes is the amount of time the label will display. And when that whole new fresh web page comes back down from the server, then the label will re-vert back to being hidden (display:none).
So, do keep in mind this VERY important concept of round trip. When you code runs behind and changes values or controls on the page? The end user does NOT see such changes until ALL code behind is done, AND THEN the page travels back down to the user. In fact, then your code behind to hide or show, can become before or after the delay in code - it will NOT update client side and in fact the order that that change label and delay will NOT matter (since the web page is STILL up on the server). So all your changes you make to the page remain up on the server until all code is done, and THEN the whole page comes back to client side to show such changes.
The other way would be to consider ajax calls - but baby steps here first, right?
You can make Button Click event asynchronous.
The following code works for me:
Private Async Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Label3.Visible = True
If TextBox1.Text = "Akilan" And TextBox2.Text = "123" Then
Label3.Text = "Please wait"
Await Task.Delay(500)
Label3.Text = ""
Form2.Show()
Hide()
Else
MsgBox("Sorry, The Username or Password was incorrect.", MsgBoxStyle.Critical, "Information")
End If
End Sub
Also check:
Async (Visual Basic)
When to use Task.Delay, when to use Thread.Sleep?
I have a textbox with multiple lines in it, each being an email address. I have a button that when clicked should read the emails from the textbox and validate that they are working emails (no spelling errors or anything). How would I go about doing something like this? For context the textbox is called emailBox
VB:
Protected Sub SaveButton(sender As Object, e As EventArgs)
End Sub
Thank you all so much in advanced!
Hi there I'm guessing by spelling errors you just mean valid email syntax.
You could use a regular expression. Like this:
Protected Sub SaveButton(sender As Object, e As EventArgs)
dim regexExpression As New Regex("^[_a-z0-9-]+(.[a-z0-9-]+)#[a-z0-9-]+(.[a-z0-9-]+)*(.[a-z]{2,4})$")
'get an array of emails
dim emails = emailBox.text.Split(",")
'loop through emails checking each one
For Each email in emails
dim valid = regexExpression.IsMatch(email)
'do whatever with result
Next
End Sub
you will need to import this too, add it to the top of your file:
Imports System.Text.RegularExpressions
then the variable 'valid' will have a value of True or False that you can do what you like with.
I have edited my answer, assuming you can use a comma to separate your emails.
Edit 2: I can't guarantee the regex will work 100% correctly. Run your own tests, tweak it if need be or find/write another.
In a web application I am writing, I populate a HTML table with a button press; after the table is populated, then the user can click another button to export the table in a CSV file.
The issue is that, while the table is properly populated at he first button pressing, it appears to be empty when the application query it at the second button press.
A few code to explain the issue:
the HTML in ASPX page
<asp:Button ID="BTNPopulate" runat="server" Text="Populate" />
<table id="Table1" style="border-width: 1px; border-color: Black; padding: 5px" cellspacing="0" runat="server" />
<asp:Button ID="BTNExport" runat="server" Text="Export" />
now the first button
Protected Sub BTNTest_Click(sender As Object, e As EventArgs) Handles BTNTest.Click
Dim row As HtmlTableRow
Dim cell As HtmlTableCell
row = New HtmlTableRow()
row.BgColor = "Gray"
cell = New HtmlTableCell()
cell.Controls.Add(New LiteralControl("Test cell"))
row.Cells.Add(cell)
Table1.Rows.Add(row)
end sub
and the table is properly populated.
I was unable to obtain any info from it and in fact if I call the .Rows.Count method anyway in the second button click code-behind
Protected Sub BTNExport_Click(sender As Object, e As EventArgs) Handles BTNExport.Click
Response.ContentType = "text/csv"
Response.AddHeader("Content-Disposition", "attachment; filename='PFExport.csv'")
CSVBuilder.Append(Table1.Rows.Count)
Response.Write(CSVBuilder.ToString)
Response.Flush()
Response.End()
End Sub
the result in the file is always 0.
On the other hand, if I call the same .Rows.Count property at the end of the populate part of the code, it properly returns the result.
I tried to use the ASPTable instead of the HTMLTable, but the issue is the same.
I assume I am missing something basic here, not sure what.
ASP.NET (or anything on the web ftm) works over HTTP. HTTP is stateless. That means that whatever you do in one request is completely lost when you make a new request.
ASp.NET webforms tries to hide this from you by using something called ViewState. It's essentially a hidden field which it sends back and forth to repopulate your page every time you do a roundtrip. When the server reconstructs the page, it reads the info from the ViewState that was sent in and rebuilds the page from those values.
The problem you're having is that the page is not repopulated yet when your click-handler is triggered. There's two ways to fix this.
(preferred): Instead of reading the data from the table in the UI, just look it up in the database again.
Set a flag on the page in the click-handler and populate the CSV on the PreRender-event.
As explained by Kenneth, my error to think the information to be preserved between requests, while HTTP is stateless.
So I investigate this from a different perspecitve and I ended up using View State to store the information locally and retrieve it to generate the CSV at the Export button press.
So, to store the info I use
ViewState("TableResultsState") = CSVBuilder.ToString
immediately after the table is populated.
For the export button, I do
With Response
.ContentType = "text/csv"
.AddHeader("Content-Disposition", "attachment; filename='PFExport.csv'")
.Write(ViewState("TableResultsState").ToString)
.Flush()
.End()
End With
As the text quantity is limited, from my research I understand this should not have adverse effects.
Again, thanks to Kenneth for pointing out my very basic misunderstanding.
I've searched their site. I just want to find the page number in the vb script. I have a report header, and if it is on page #1 then I want a page break after.
This code should do the trick. It's the PrintOnPage event handler for a label in your Report Header.
Private Sub xrLabel1_PrintOnPage(ByVal sender As Object, ByVal e As DevExpress.XtraReports.UI.PrintOnPageEventArgs) Handles xrLabel1.PrintOnPage
If e.PageIndex > 0 Then
ReportHeader.PageBreak = DevExpress.XtraReports.UI.PageBreak.None
Else
ReportHeader.PageBreak = DevExpress.XtraReports.UI.PageBreak.AfterBand
End If
End Sub
Note that the PageIndex value is zero-indexed. Also, the page index is only available (as far as I know) in the PrintOnPageEventArgs, so this won't work in a Before/AfterPrint event.
See this knowledge base article for reference.
I have an SSRS report that is displayed to users in the ASP.NET ReportViewer control. The report has many parameters and we're using the parameter prompts that the ReportViewer control offers. Depending on a certain parameter of the report, we only need to have the user prompted for a subset of the rest of the report parameters.
We could have used linked reports and hide the appropriate parameters, but there are many possible combinations to that first parameter (it's multi-valued), so we'd rather not do that. Instead, we have an ASP.NET ListBox that controls the first parameter and when it's selection is changed, we are using the ReportViewer.ServerReport.SetParameters() function to hide/show parameters (it takes in an array of ReportParameter and the ReportParameter constructor takes in a boolean to hide/show the parameter).
Here's the issue. Everything works fine in our development environment. When we deploy the report and the ASP.NET site to the production environment, parameters never get shown when those SetParameters() calls are invoked. We know the code is called because we put some debugging output to make sure. The code to hide parameters is working fine. It's just the code that should cause certain parameters to show up again doesn't work. Not only does it not show up the parameter prompts, but the Visible property of the parameter does not get set to true (checked by using ReportViewer.ServerReport.GetParameters()).
We have SQL Server 2005 SP3 installed in both environments, and the same version of the report viewer control (Microsoft.ReportViewer.WebForms.dll). Any ideas what could be wrong? Any workaround ideas? If you have questions, leave comments.
Edit: After further investigation, we isolated the problem further. I made a simple report with just 1 parameter without any DB connection. Then I made an aspx page with 2 buttons and a ReportViewer control hooked up to that report. 1 button hides the parameter and 1 button shows the parameter (using the SetParameters() function, as mentioned above). Even with this simple scenario, the hide/show buttons work fine in the development environment, but we still have the same issue in the production environment (the show button doesn't work). We also tried this on another server on the network in the production environment, and we have the same issue. So everything seems to work fine in the development environment, but on 2 different servers outside that environment we seem to be getting the same issue.
Edit2: Below is the code behind for the test report page. The page has a ReportViewer, 2 Buttons, and a Label for debug output. When the showing of hidden parameters doesn't work, the Label even shows that the Visible property is still false after the call to ShowParameter.
Public Partial Class TestReportPage
Inherits System.Web.UI.Page
Public Sub HideParameter(ByVal parameterName As String)
Dim parameters As ReportParameterInfoCollection = ReportViewer1.ServerReport.GetParameters()
ReportViewer1.ServerReport.SetParameters(New ReportParameter() {New ReportParameter(parameterName, GetParameterDefaults(parameterName, parameters), False)})
parameters = ReportViewer1.ServerReport.GetParameters()
lblTest.Text &= "Hide param " & parameterName & "; Is Visible: " & parameters(parameterName).Visible & "<br>"
End Sub
Public Sub ShowParameter(ByVal parameterName As String)
Dim parameters As ReportParameterInfoCollection = ReportViewer1.ServerReport.GetParameters()
ReportViewer1.ServerReport.SetParameters(New ReportParameter() {New ReportParameter(parameterName, GetParameterDefaults(parameterName, parameters), True)})
parameters = ReportViewer1.ServerReport.GetParameters()
lblTest.Text &= "Show param " & parameterName & "; Is Visible: " & parameters(parameterName).Visible & "<br>"
End Sub
Public Shared Function GetParameterDefaults(ByVal parameterName As String, ByVal parameters As Microsoft.Reporting.WebForms.ReportParameterInfoCollection) As String()
Dim paramDefaults() As String = {}
Dim i As Int16 = 0
For Each paramValue As String In parameters(parameterName).Values
ReDim Preserve paramDefaults(i)
paramDefaults(i) = paramValue
i = i + 1
Next
Return paramDefaults
End Function
Protected Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
HideParameter("foo")
End Sub
Protected Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
ShowParameter("foo")
End Sub
End Class
Just for anyone else who ever has this issue, here's the reason we were having this issue:
The issue was due to a difference in the environments. Even though we had the ReportViewer DLL being copied into the bin folder of the project (and thus copied to where the project was hosted), this issue w/the params is a bug in older versions of the ReportViewer control. You need to get the Microsoft Report Viewer Redistributable 2005 SP1 to fix this issue. Apparently we had this fix installed in the development environment. For some reason the ReportViewer DLL was the same version on both sides though. This could be because the DLL was actually being accessed from a different location.