I have a GridView that displays user info along with two template fields with imagebuttons. One is to open up a detailsview to edit user information. The other is to edit the user's password.
In my Code Behind, I have 3 IIf statements that check for certain criteria. Based on certain combinations of this criteria, I want the ImageButtons to either show/not show appropriately.
Here is my code behind:
Protected Sub gvUsers_RowDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) Handles gvUsers.RowDataBound
Dim isProvisioned As Boolean
Dim acceptedToS As Boolean
Dim isSuspended As Boolean
'hide password change option for users that have not yet been provisioned or have not accepted ToS Agreement or have been suspended'
If e.Row.RowType = DataControlRowType.DataRow And _
DirectCast(sender, GridView).EditIndex <> e.Row.DataItemIndex Then
isProvisioned = IIf(String.IsNullOrEmpty(e.Row.DataItem(GUser.columns.DATEADDED).ToString), False, True)
acceptedToS = IIf(String.IsNullOrEmpty(e.Row.DataItem(GUser.columns.TOSTIMESTAMP).ToString), False, True)
isSuspended = IIf(String.IsNullOrEmpty(e.Row.DataItem(GUser.columns.SUSPENDDATE).ToString), False, True)
Dim btnAdminEdit As ImageButton = DirectCast(e.Row.FindControl("btnAdminEdit"), ImageButton)
Dim btnAdminSelect As ImageButton = DirectCast(e.Row.FindControl("btnAdminSelect"), ImageButton)
btnAdminEdit.Visible = Not (isSuspended) AndAlso isProvisioned AndAlso acceptedToS
btnAdminSelect.Visible = isProvisioned
Else
gvUsers.EmptyDataText = "No records found matching specified criteria."
End If
End Sub
I don't know what changed because this code DID work at one point. However, when I test the page, both imagebuttons seem to show up no matter what. While debugging, I also saw that it seemed to "evaluate" each row the same way. As in, for each row that went through my IIf statements, it always returned the same values, even if it was not true.
I have a hunch that it's taking the first row's values and reusing it some how, or evaluating the same row; that's why it always returns the same values and always shows the imagebuttons, even though they are not supposed to be visible according to my IIf statements.
Any help is greatly appreciated as I'm not too sure how to resolve it from here.
Well, after delving a little deeper, I found what was causing the problem.
The last change I made before seeing this problem was the addition of another column to be displayed in the GridView. This distorted the index of the columns so my IIF statements were not checking the correct datafields and thus, were evaluating incorrectly.
So, the code behind I posted does work and luckily proved that I wasn't going crazy. The logic is correct!
Thanks to those who took time to glance at this question!
Related
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>
I have checklist with multiple selections now the user will preview the form in another webform after press preview button the issue here that the checklist not populated in the other form with all selections and only item selected
In first form I wrote the below code:
Dim Fruit as String = ChkFruit.SelectedValue
Redirect.response(home.aspx?"fruit=" + Fruit)
In second form I wrote the below code:
ChkFruit1.Selectedvalue = QueryString("Fruit")
Well in your example posted code, if we are to ONLY PASS one selected value, then what you have is a good start.
However, VERY NEW BIG LARGE MASSIVE different problem is now we allow "many" selections in the check box list. So with a NEW HUGE LARGE DIFFERENT kind of question and problem?
Then we will as a result need a VERY different solution. The large new big massive problem here is how to pass 1 value, or 15 choices? This of course as noted is quite a more difficult problem and challenge.
For passing a "list" or "array" of a whole bunch of possbile choices, then I suggest we do NOT use the URL parmaters (query parms in the URL).
So, what we need here is to build up some "list" of choices from the check box list, and pass that to the 2nd page. Now there are more ways to do this then there are flavors of ice cream, and we have a LOT of choices.
However, I going to suggest creating a List of chocies, and we pass that to the 2nd page we jump to.
So, our markup and button in the first page can look like this:
<asp:CheckBoxList ID="CheckBoxList1" runat="server">
<asp:ListItem>Apple</asp:ListItem>
<asp:ListItem>Grapes</asp:ListItem>
<asp:ListItem>Bananna</asp:ListItem>
<asp:ListItem>Cherry</asp:ListItem>
</asp:CheckBoxList>
<br />
<br />
<asp:Button ID="Button2" runat="server" Text="Submit" Width="158px" />
Ok, above is quite nice - not complex.
Now, for our button code? We need to build up, get/grab/obtain the list of selected values - that's what we will pass to the 2nd page.
So, above looks like this:
So, now our button/submit code on this web page:
Protected Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim MyCheckList As List(Of String) = New List(Of String)
For Each MyItem As ListItem In CheckBoxList1.Items
If MyItem.Selected Then
MyCheckList.Add(MyItem.Value)
End If
Next
Session("MyCheckList") = MyCheckList
Response.Redirect("Test2.aspx")
End Sub
So, in place of "url messay parmaters"?
We create a List type variable (they are somewhat the same as an array()
We then add all selected items to that new list
We then stuff/place the new list into Session()
We then jump to the 2nd web page with the Reponse.Redirect
Ok, so now, on the target web page, we have to get that list we passed.
Now, on the 2nd page, the code ONLY needs that list.
but, lets assume that we have the same check box list on that 2nd page - and we want to fill out - show/display/have the Check box list show the same choices.
WHAT IS IMPORTANT here is how we are free to use the "list" we passed to that 2nd page. I can do anything with that nice list , but we have this:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not IsPostBack Then
Dim MyCheckList As List(Of String) = Session("MyCheckList")
' display the list of passed check box values
For Each MySelected As String In MyCheckList
Debug.Print(MySelected)
Next
' or say fill out a check box list we have on this new page -
' process EACH check box list item
' check if in our list - if yes, then check box/select it
For Each MyItem As ListItem In CheckBoxList1.Items
MyItem.Selected = MyCheckList.Contains(MyItem.Value)
Next
End If
End Sub
So, in this 2nd page, we demonstrate two examples.
First part of code example - JUST display the list of previous selections. You are thus now free to for each loop and process the check box list of selections.
Second part of code example. We actually take that list and check box a whole new check box list we have on the 2nd target page. Now, I doubt the check box list would be the same and duplicated on that 2nd page, but this code example shows how we could display the check box list "again" on the 2nd new target page.
And the code also demonstrates how to loop/process the list of selections, which is really at a the end of the day the most valuable part of this example code
So, in our 2nd page, if we have this markup:
<asp:CheckBoxList ID="CheckBoxList1" runat="server">
<asp:ListItem>Apple</asp:ListItem>
<asp:ListItem>Grapes</asp:ListItem>
<asp:ListItem>Bananna</asp:ListItem>
<asp:ListItem>Cherry</asp:ListItem>
</asp:CheckBoxList>
<br />
Then we would see this:
So when you have MORE then just one value to pass to the next page?
Then you can use session() in place of messy and difficult to use URL "parmaters". And those URL paramters are not all that great for passing "many" values like this new problem required.
If we were to only pass ONE value, and ONE selection, then the URL parmaters would be ok to use. But now since we need to pass "many" values then using session() to pass that information to the 2nd target page becomes a whole lot less work and efforts on your part.
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.
I am using ASP.NET in Visual Studio 2010.
I have a website that features a shopping cart, the user can signup which has validation using the RequiredFieldValidator control meaning they must enter something for certain fields e.g. Address 1 / E-Mail. This is also tied to a Database which for these fields does not allow null values.
My issue that is after logging in, adding items to cart, quantities etc, I have a confirmation order page - similar to most online shopping websites were the shopping basket is displayed along with the user's Customer Details, which is shown through a DetailsView, connected to a SqlDataSource which is running a query that just displays their shipping details as previously entered.
However, if I say select Edit, which is using the DetailsView's own property and change the Address1 line to nothing, the DetailsView sends it as null value after accepting and as a result the whole thing crashes.
I have tried examples like:
Protected Sub DetailsView1_PageIndexChanging(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.DetailsViewPageEventArgs) Handles DetailsView1.PageIndexChanging
Try
Catch ex As Exception
lblError.Text = "Please verify changes made to Customer Details."
End Try
End Sub
Protected Sub DetailsView1_ItemUpdating(ByVal sender As Object, ByVal e As DetailsViewUpdateEventArgs) Handles DetailsView1.ItemUpdating
Try
Catch ex As Exception
lblError.Text = "Please verify changes made to Customer Details."
End Try
End Sub
Protected Sub detailsView1_ItemUpdated(ByVal sender As Object, ByVal e As DetailsViewUpdateEventArgs) Handles DetailsView1.ItemUpdating
Try
Catch ex As Exception
lblError.Text = "Please verify changes made to Customer Details."
End Try
End Sub
So basically Try / Catch statements which has worked for everything else. But because I can't get access to any proper code behind for the DetailsView since it's just taken from Visual Studio I'm stumped. Has left me curious now, looked about here and elsewhere and couldn't find much, anything seemed similar to what I've tried there but they don't make a difference.
I want to try and create/find some form of Error Handling for this situation, similar to registering, either not proceeding with sending to the server if left blank or display a message.
This is the main part of the error:
[SqlException (0x80131904): Cannot insert the value NULL into column 'Address1', table 'C:\USERS\xxxx\PROJ (2)\PROJ\APP_DATA\ORDERS.MDF.dbo.Customer'; column does not allow nulls. UPDATE fails.
The statement has been terminated.]
Something simple I'm missing? Was considering the option of creating text boxes instead and connecting to the database individually, but that's a completely different route to this and there is quite nice, simple customizable options with the DetailsView.
Well...typical after spending weeks confused by this one I managed to get it just after posting the question.
For anyone interested in this I used the 'If e.Exception Is Nothing Then' statement within the code similar to the two bottom examples I tried, THEN, used a Try/Catch statement.
Really weird... So I'm trying to save the page index of my gridview in a Session Variable and then reset the index when the user navigates back to the gridView. Here's my code below;
Protected Sub Page_PreRender(ByVal sender As Object, ByVal e As EventArgs)
If Not Page.IsPostBack Then
If Not Session("CurrentPage") Is Nothing AndAlso
Session("CurrentPage") <= GridView1.PageCount Then
GridView1.PageIndex = Session("CurrentPage")
End If
End If
End Sub
Well the weird thing is that when I breakpoint on the second IF above and hover over pageCount it says it's 0. If I then go into my watch window and look at it (0 once again), then go back to my code and hover again it's 2 (which it should be)! I can then Continue past the break point and the page displays on page 2 as it should. However, and this is where it gets really weird, if I remove the breakpoint and run it I end up on page 1! So it's as if the PageCount hasn't updated unless I've put a breakpoint on it and specifically looked at it. Anyone explain this behaviour and how to get around it?!
UPDATE
Here's a pic of the values of the variables in question. You can see the PageIndex wasn't updated because it never entered the IF statement because moments earlier the PageCount was 0!! I can't be the only one stumped by this :/
Image of variable values:
I guess you may need to cast your Session value to Integer
If Not Session("CurrentPage") Is Nothing AndAlso
DirectCast(Session("CurrentPage"),
Integer) <= GridView1.PageCount Then
GridView1.PageIndex = DirectCast(Session("CurrentPage"),Integer)
End If
Ok bit hacky but it works. Simply used;
If Not Session("CurrentPage") Is Nothing Then
GridView1.PageIndex = DirectCast(Session("CurrentPage"), Integer)
End If
Couldn't get the GridView.PageCount to equal 2 except by going into the WatchWindow and refresh the value field (would be hard to explain to your everyday online user how to do that so that wasn't really an option :P ). So I tried just leaving it out. Works fine now. Could possibly run into a page does not exist error but I imagine it would be quite unlikely as the number of pages doesn't change much at all and Session("CurrecntPage") variable is updated quite regularly.