Dropdown in listview SelectedIndexChanged doesn't work first time but does after - asp.net

I've searched high and low, I can't seem to find out what's happening with this. I've simplified the code, but I really have taken it back to as basic as this and still have the same problem.
I have a drop down list in a a repeater (in a Web Form with master page):
<asp:DropDownList ID="TicketQuantityDDL" runat="server" CssClass="qtyddl" AutoPostBack="true" OnSelectedIndexChanged="TicketQuantityDDL_SelectedIndexChanged" CausesValidation="false" SelectedIndex='<%# CInt(Eval("Quantity")) - 1%>'>
<asp:ListItem Value="1">1</asp:ListItem>
<asp:ListItem Value="2">2</asp:ListItem>
<asp:ListItem Value="3">3</asp:ListItem>
<asp:ListItem Value="4">4</asp:ListItem>
<asp:ListItem Value="5">5</asp:ListItem>
<asp:ListItem Value="6">6</asp:ListItem>
</asp:DropDownList>
Handler
Protected Sub TicketQuantityDDL_SelectedIndexChanged(sender As Object, e As EventArgs)
myLiteral.text = "Selected Index Changed handled..."
End Sub
The first time the page is loaded if I change the DDL the the page is posted back - the selected index change handler is NOT fired (I've stepped through the code, page.ispostback is true). Every time after the handler works unless the page is full reloaded.
Things I've tried:
Manually adding a handler OnItemCreated
Manually adding a handler OnItemDataBound
Manually registering the control for async postback with scriptmanager
Using OnClientSelectedIndexChanged to trigger postback from the client
Removing AutoPostBack and all of the above again...
I've used Page.Request.Params("__EVENTTARGET") to verify that when the partial postback is fired that the control is the drop down.
Even though viewstate is enabled I've tried specifying this for the control and the page directly.
Disabling validation.
I've tried not binding the value of the drop down and just leaving it
as is with no selected value and then manually setting the initial
selected value - no dice.
Tried removing update panel, same issue.
Things that are DEFINITELY not happening here.
I'm not rebinding on post back if not page.ispostback... databind...
I'm not selecting the same value/first item in the drop down
This isn't an auto ID problem, the controls ID stay the same through postbacks.
I'm not doing anything funky other than binding the repeater to a list of objects.
Why isn't the handler firing the first time? After the first time everything works exactly as intended.
Update
I've replicated the exact same behaviour in a list view. Due to time constraints I've used another approach but I'd really like to know how to fix this or at least know why it doesn't work.
Update 2
I've tested the functionality with a bog standard web form and it functions correctly. Something is up with this being in a contentplaceholder from a masterpage, the script manager or update panel. It's as if the event handler for the dropdown is only registered after the first post back, I've tried registering the handler in DataBound and also in the page LoadComplete events, the same thing still happens.
Update 3
I've since changed it to a list view, I'm having the exact same issue though.
This is on a web form with master page, the master page contains the script manager, the list view is in an update panel, although I've tried removing this and I still have the same issue. I've not included the onselectedindexchanged code, I've made it as simple as changing the text of a literal - doesn't work first post back, does the second.
I had originally specified the list items manually but have changed this to programatically at itemDataBound, still no difference.
As I stated above when I check which control caused the postback it's definitely the ddl, it just doesn't fire selectindexchanged the first time. I've also tried specifying the OnSelectedIndexChange in the control itself, still no dice.
Page load ,bind, list view and on item created code.
Page Load
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
Dim _Basket = SessionHandler.getSessionObject(SessionHandler.SessionObjects.Basket)
If _Basket Is Nothing OrElse DirectCast(_Basket, BasketContainer).BasketItemList.Count = 0 Then
BasketSectionContainer.Visible = False
alertLiteral.Text = AlertGenerator.GetAlertHTML("No Items in Basket", "There are no items in your basket, please use the menu above to navigate the site.", AlertGenerator.AlertType.warning)
If _Basket IsNot Nothing Then SessionHandler.removeSessionObject(SessionHandler.SessionObjects.Basket)
Exit Sub
Else
Dim lBasket = DirectCast(_Basket, BasketContainer)
BindBasket(lBasket)
End If
End If
End Sub
Bind
Private Sub BindBasket(lBasket As BasketContainer)
basketListView.DataSource = lBasket.BasketItems
basketListView.DataBind()
bindTotals(lBasket) 'This just sets text of literals on the page outside of the listview
If lBasket.Postage Then
PostageDDL.visible = True 'This is outside of the list view also
End If
End Sub
Item Created
Private Sub basketListView_ItemCreated(sender As Object, e As ListViewItemEventArgs) Handles basketListView.ItemCreated
Dim QtyDDL As DropDownList = DirectCast(e.Item.FindControl("TicketQuantityDDL"), DropDownList)
AddHandler QtyDDL.SelectedIndexChanged, AddressOf TicketQuantityDDL_SelectedIndexChanged
End Sub
_Item Data Bound _
Private Sub basketListView_ItemDataBound(sender As Object, e As ListViewItemEventArgs) Handles basketListView.ItemDataBound
Dim data As BasketItem = DirectCast(e.Item.DataItem, BasketItem)
Dim QtyDDL As DropDownList = DirectCast(e.Item.FindControl("TicketQuantityDDL"), DropDownList)
For i As Integer = 1 To 6
QtyDDL.Items.Add(New ListItem(i.ToString, i.ToString))
Next
QtyDDL.DataTextField = data.BasketItemID.ToString 'no command arg for DDL so using this, I've tested without, doesn't make a difference.
Select Case data.BasketType
Case BasketInfo.BasketItemType.DiscountedTickets, BasketInfo.BasketItemType.Tickets, BasketInfo.BasketItemType.Goods
'tickets and goods...
QtyDDL.Items.FindByValue(data.Quantity.ToString).Selected = True
Case Else
'non ticket or goods type, disable quantity selection
QtyDDL.Items.FindByValue("1").Selected = True
QtyDDL.Enabled = False
End Select
End Sub
_List View _
<asp:ListView ID="basketListView" runat="server">
<LayoutTemplate>
<table class="cart-table responsive-table">
<tr>
<th>Item</th>
<th>Description</th>
<th>Price</th>
<th>Quantity</th>
<th>Total</th>
<th></th>
</tr>
<asp:PlaceHolder ID="itemPlaceholder" runat="server" />
</table>
<table class="cart-table bottom">
<tr>
<th>
<asp:Button ID="ApplyDiscountCodeButton" runat="server" CssClass="button color pull-right" Text="Apply Code" />
<asp:TextBox ID="DiscountCodeTextBox" runat="server" CssClass="discount-tb pull-right" />
</th>
</tr>
</table>
<div class="clearfix"></div>
</LayoutTemplate>
<ItemTemplate>
<tr>
<td>
<img src="/images/shows/<%# Eval("imageURL")%>.jpg" alt="<%#Eval("BasketItemTitle")%>" class="basketimg" /></td>
<td class="cart-title">
<%#Eval("BasketItemTitle")%>
<br />
<%# String.Format("{0:dddd} {1} {0:MMMM yyyy} | {0:HH:mm}", Eval("PerformanceStarts"), Eval("OrdinalDay"))%>
<br />
<%# Eval("VenueTitle")%>
</td>
<td>
<%#Eval("PriceBandType")%>
<br />
# <%# String.Format("{0:c}", Eval("PriceBandValue"))%>
</td>
<td>
<asp:DropDownList ID="TicketQuantityDDL" runat="server" CssClass="qtyddl" AutoPostBack="true" ClientIDMode="Static" />
</td>
<td class="cart-total"><%#String.Format("{0:c}", Eval("BasketItemTotalValue"))%></td>
<td>
<asp:LinkButton ID="RemoveLinkBtn" runat="server" CssClass="cart-remove" CommandName="RemoveBasketItem" CommandArgument='<%#Eval("BasketItemID")%>' />
</td>
</tr>
</ItemTemplate>
</asp:ListView>

Since the Dropdown in inside the repeater, you can try the following Option instead.
Add OnItemCommand to the repeater. This should definitely Trigger the Event on selection Change in the Dropdown. Then in the OnItemCommand you Need to cast the Sender to DropDownList to be able get the selected value of the dropdown

You have to register the dropdown list event like this.
protected virtual void OnRepeaterItemCreated(object sender, RepeaterItemEventArgs e)
{
DropDownList dropdown = (DropDownList)e.Item.FindControl("TicketQuantityDDL");
dropdown.SelectedIndexChanged += TicketQuantityDDL_SelectedIndexChanged;
}
And also add this piece of code in your repeater.
OnItemCreated="OnRepeaterItemCreated"
And then you can do the selected index changed event like this.
protected void TicketQuantityDDL_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList mydropdownlist = (DropDownList)sender;
Response.Write(mydropdownlist.SelectedValue);
}

protected void dropdownlist1_SelectedIndexChanged(object sender, EventArgs e)
{
DropDownList ddlListFind = (DropDownList)sender;
ListViewItem item1 = (ListViewItem)ddlListFind.NamingContainer;
DropDownList getDDLList = (DropDownList)item1.FindControl("dropdownlist1");
Label lblMessage = (Label)item1.FindControl("lblMsg");
lblMessage.Visible = true; lblMessage.Text = "dropDown text is : " + getDDLList.SelectedItem.Text + " and value is : " + getDDLList.SelectedItem.Value;
}

Related

How to get Repeater's current ItemIndex in code behind

While Container.ItemIndex as a way to get current repeater's item index in data binding expression works perfectly fine <%# Container.ItemIndex %>, it does not work in pure code behind. Container is not declared or inaccessible.
How can I get repeater's current item index here:
<ItemTemplate>
<% If Container.ItemIndex = 2 Then %>
TRUE/some longer HTML here/
<% Else %>
false/some longer HTML here/
<% End If %>
</ItemTemplate>
EDIT
For cases with not much HTML code this will work, but I am looking for Code Render Block solution as per example above.
<%#: If(Container.ItemIndex = 2, "TRUE", "false") %>
Ok, just drop in a button and pick up the repeter row.
So, say we have this repeater markup:
<asp:Repeater ID="Repeater1" runat="server">
<ItemTemplate>
<div style="border-style:solid;color:black;width:290px;float:left;padding:10px">
<div style="padding:5px;text-align:right">
Hotel Name: <asp:TextBox ID="txtHotelName" runat="server" Text ='<%# Eval("HotelName") %>' />
<br />
First Name: <asp:TextBox ID="txtFirst" runat="server" Text ='<%# Eval("FirstName") %>' />
<br />
Last Name: <asp:TextBox ID="txtLast" runat="server" Text ='<%# Eval("LastName") %>' />
<br />
City: <asp:TextBox ID="City" runat="server" Text ='<%# Eval("City") %>' />
<br />
Province: <asp:TextBox ID="Province" runat="server" Text ='<%# Eval("Province") %>'/>
<br />
Active: <asp:CheckBox ID="chkActive" runat="server" Checked = '<%# Eval("Active") %>'/>
<br />
<asp:Button ID="cmdRowC" runat="server" Text="Row Click" OnClick="cmdRowC_Click"/>
</div>
</div>
<div style="clear:both;height:5px"></div>
</ItemTemplate>
</asp:Repeater>
and our code behind to fill this repeater:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If IsPostBack = False Then
LoadGrid()
End If
End Sub
Sub LoadGrid()
Using cmdSQL As New SqlCommand("SELECT * FROM tblHotels ORDER BY HotelName",
New SqlConnection(My.Settings.TEST3))
cmdSQL.Connection.Open()
Repeater1.DataSource = cmdSQL.ExecuteReader
Repeater1.DataBind()
End Using
End Sub
And we now have this:
So now the button code. Note how I just dropped in a standard button.
But, we now can't double click on the button to automatic wire up and create a event.
BUT YOU CAN do this to create a event:
In the button code markup, type in OnClick=
WHEN YOU HIT "=", then intel-sense will pop up a dialog for you to create a button click event like this:
So, now click on create new event. It "seems" like nothing occured, but if we flip to code behind you find the click event stub.
So, now in our click event code we can easy pick up the current repeater row, the values and yes even the index.
The code works like this:
Protected Sub cmdRowC_Click(sender As Object, e As EventArgs)
Dim cBtn As Button = sender
Dim rRow As RepeaterItem = cBtn.Parent
Debug.Print("Row clicked = " & rRow.ItemIndex)
Debug.Print("First Name = " & DirectCast(rRow.FindControl("txtFirst"), TextBox).Text)
Debug.Print("Last Name = " & DirectCast(rRow.FindControl("txtLast"), TextBox).Text)
Debug.Print("Hotel Name = " & DirectCast(rRow.FindControl("txtHotelName"), TextBox).Text)
End Sub
output:
Row clicked = 1
First Name = Darcy
Last Name = Caroll
Hotel Name = Athabasca Hotel
So, just drop in a plane jane button. When you click on it the event stub runs, and as you can see, we pick up the "Repeater row item".
From that row, we can get the row index, and of course pluck out any other control value from that row using find control.
eg:
Dim txtHotel as TextBox = rRow.FindControl("txtHotel")
debug.print ("Hotel name = " & txtHotel.Text)
So, once you have the repeater row, you don't need some container.ItemIndex expression, since the row item lets you get the given index row with:
rRow.ItemIndex
So, ItemIndex is available, and is avilable regardless if you have or include or use the conttin.ItemIndex in the markup.
There is VERY LITTLE need to mess around with that code in the markup.
Note how VERY clean and simple the above is. I suggest you MAKE HUGE efforts to avoid dumping vb code inside of the markup like you are doing. If you even want to convert to c#, or even just maintain that code? Put that code in the code behind area - not in the markup.
As above shows, for repeating data etc., you can use a Repeater, or even often I use a listview - as it allows a repeating layout to be created automatic for you, and without having to write looping code.
******************** EDIT ***************************
Ok, now that we have this working, say we wanted to put in a message in the repeater that
This hotel is Active
or
This hotel is NOT active!
Ok, so in our markup, we could drop in a label like this:
And now from the repeater property sheet, double click here to create the item data bound event:
It is now a simple matter to put in our code logic for each row like this:
Protected Sub Repeater1_ItemDataBound(sender As Object, e As RepeaterItemEventArgs) Handles Repeater1.ItemDataBound
Dim rRow As RepeaterItem = e.Item
Dim ckbox As CheckBox = rRow.FindControl("chkActive")
Dim MyLabel As Label = rRow.FindControl("Label1")
If ckbox.Checked Then
MyLabel.Text = "This Hotel is Active!!!"
Else
MyLabel.Text = "Not active!"
End If
End Sub
And output is now this:
So, once again, to conditional format the repeater, add color to active hotel, or whatever? Use the item bound event.
Say i wanted add to above that the HotelName is to be color blue when active, then we could do this:
Protected Sub Repeater1_ItemDataBound(sender As Object, e As RepeaterItemEventArgs) Handles Repeater1.ItemDataBound
Dim rRow As RepeaterItem = e.Item
Dim ckbox As CheckBox = rRow.FindControl("chkActive")
Dim MyLabel As Label = rRow.FindControl("Label1")
If ckbox.Checked Then
MyLabel.Text = "This Hotel is Active!!!"
Else
MyLabel.Text = "Not active!"
End If
Dim txtHotel As TextBox = rRow.FindControl("txtHotelName")
If ckbox.Checked Then
txtHotel.BackColor = Drawing.Color.AliceBlue
End If
End Sub
Again, nice easy clean code - no mess markup. We seperate the code logic from the markup.
Output now is this:
Again, note how we did not even write ANY looping code here!!!!
So you want to leverage the built in options for the repeater, and for a GridView, listView, and a repeater?
Use the row data bind event - it lets you format, even do math, or whatever you want for EACH row of the repeating controls. And as you can see, its plain jane easy to write code as a bonus.

My DropDownList SelectedIndex returns to 1 when I click submit

I have two dropdownlists:
First one:
<asp:DropDownList ID="Drddl" class="form-control form-control-sm" Height="30" runat="server"
Width="350" Enabled="False" AppendDataBoundItems="true" AutoPostBack="true" DataTextField="FullName" DataValueField="Name">
</asp:DropDownList>
and gets filled on page load :
If Not Page.IsPostBack Then
FillDrData()
End If
The second:
<asp:DropDownList ID="Drddl" class="form-control form-control-sm" Height="30" runat="server" Width="350" Enabled="False" AppendDataBoundItems="true" AutoPostBack="true" DataTextField="FullName" DataValueField="Name"></asp:DropDownList>
and gets filled on SelectedIndexChanged of first one:
Private Sub Drddl_SelectedIndexChanged(sender As Object, e As EventArgs) Handles Drddl.SelectedIndexChanged
FillAgenceData()
End Sub
My question is:
Everything is working fine until I click submit button that read selected items from both dropdownlists and save it in SQL database. The Agenciesddl selecteditem always return to 1.
Be mindful of the postbacks of each dropdownlist. Quick and dirty way would be to set the selected values in ViewState or Session variables then get the variables on Submit. See below for rough example (pardon the c#)
Private void Drddl_SelectedIndexChanged(sender As Object, e As EventArgs)
{
ViewState["DrddlVal"] = Drddl.SelctedValue;
}
private void submit(sender As Object, e As EventArgs)
{
string dbparmval = ViewState["DrddlVal"].ToString();
}
As usual the answer is very simple.
the DataValueField property of DropDownList must be UNIQUE
when SelectedIndexChanged event triggered, the DropDownList goes to first value if he find more than one item has same value.
thanks for this article:
enter link description here
thanks everyone..

UpdatePanel async postback not updating content

I have an issue very similar to this question. There is a dropdown on my page that causes a postback, during which the ImageUrl property of an ASP:Image is changed. When that postback happens, any value that is in the FileUpload is cleared. That's the problem I'm trying to solve, but I ran into this issue in the process.
I'm trying to solve the problem by wrapping the dropdown and image in an UpdatePanel. Here is my ASP markup:
<asp:UpdatePanel ID="upPanel" runat="server">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="myDropdown"
EventName="SelectedIndexChanged" />
</Triggers>
<ContentTemplate>
<tr valign="top">
<td>Tag:</td>
<td>
<asp:DropDownList ID="myDropdown" runat="server"
AppendDataBoundItems="true" DataTextField="Name"
DataValueField="ID" AutoPostBack="true">
<asp:ListItem Value="" />
</asp:DropDownList>
</td>
</tr>
<TR vAlign="top">
<TD width="150">Thumbnail:</TD>
<TD>
<asp:Image id="imgThumbnail" Runat="server"
AlternateText="No Image Found"
Visible="false"></asp:Image><BR>
</TD>
</TR>
</ContentTemplate>
</asp:UpdatePanel>
EDIT: my code-behind doing the update is here:
Private Sub myDropdown_SelectedIndexChanged(ByVal sender As Object, ByVal e As EventArgs) Handles myDropdown.SelectedIndexChanged
If (myDropdown.SelectedValue <> "-1") Then
imgThumbnail.ImageUrl = Application("AppPath") + "/Modules/Broadcaster/ImageGen.ashx?tag=" + myDropdown.SelectedValue
Else
imgThumbnail.ImageUrl = Application("AppPath") + "/Modules/Broadcaster/ImageGen.ashx?defaultTag=" + _modID.ToString()
End If
End Sub
I can see the async postback happening in FireBug, but the image URL does not change. What am I doing wrong?
You're missing the code that's doing the update (the code that is called by the selected index changing within the dropdown); however, I'm going to venture a guess that your problem is being caused because you are loading the DDL through a control instead of programmatically.
The reason you may be running into this issue is because the page load function is called before the datasource controls are populated, which means that the DDL is not populated by the time you are looking for a value, thus your image is coming up with a blank.
Example:
Dim sTemp As String = "images/myimagenumber" & myDropdown.SelectedIndex & ".jpg"
This will return "images/myimagenumber.jpg" as the value of the sTemp string because there is no value or index selected the the moment the page loads.
I suggest you load the values of the dropdownlist manually (programmatically) and then in the page_load subroutine make sure that it's only repopulating the dropdown when the page loads for the first time.
VB.Net Example:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
If Page.IsPostback = False Then
runDBLFillSubHere()
End If
'Run Rest of Code Here'
Sub
I've run into this a couple times over the years and it always ends up being because the DDL isn't populated before I am accessing it.

CheckBox Controls in Repeater not maintaining state

Bit confused about this. I was under the impression that if you added server controls to the ItemTemplate of a repeater then the ID's assigned to those controls would persist across postbacks and the state would be maintained. But it doesn't seem to be happening. Here's my ItemTemplate:
<asp:HiddenField ID="hidPending" runat="server" value="<%# DataBinder.Eval(Container.DataItem, "Id")%>" />
<td class="leftpadd"><uc:restrictedtext ID="uclblCategory" runat="server" Width="125" /></td>
<td style="border-left:1px solid #528ABD;" class="leftpadd"><%# DataBinder.Eval(Container.DataItem, "SelectedOptions")%></td>
<td style="border-left:1px solid #528ABD;" class="leftpadd"><%# DataBinder.Eval(Container.DataItem, "Price.IncludingTax", "{0:C}")%></td>
<td style="border-left:1px solid #528ABD;" class="leftpadd"><%# DataBinder.Eval(Container.DataItem, "ExtrasCost", "{0:C}")%></td>
<td style="border-left:1px solid #528ABD;" class="leftpadd"><%# DataBinder.Eval(Container.DataItem, "Quantity", "{0:000}")%></td>
<td style="border-left:1px solid #528ABD;" class="leftpadd"><asp:CheckBox ID="chkPendingItems" runat="server" /></td>
Which populates fine. What I'm looking to happen is for the user to be able to select certain items from the repeater using the checkbox and "process" them (i.e. perform some data operations on those items) on clicking a button which is outside the repeater. Here's my button click code:
Private Sub lnkPendingProcessSelected_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles lnkPendingProcessSelected.Click
For Each rItem As RepeaterItem In rptPendingItems.Items
If rItem.ItemType = ListItemType.Item Or rItem.ItemType = ListItemType.AlternatingItem Then
Dim chk As CheckBox = DirectCast(rItem.FindControl("chkPendingItems"), CheckBox)
If chk.Checked Then
Dim orderItemId As Integer
Dim hid As HiddenField = DirectCast(rItem.FindControl("hidPending"), HiddenField)
orderItemId = CInt(hid.Value)
My.Application.ManagerFactory.OrderManagerInstance.ChangeOrderItemStatus(orderItemId, Concrete.Cms.DataTransferObjects.OrderItemStatus.Processing)
End If
End If
Next
End Sub
But if you step through this, the checkboxes are found and assigned correctly but their Checked attribute is always False. Anyone have any suggestions as to why state isn't being maintained and what I can do about it?
Based on CyberDude's comment, you're probably reseting the values when you databind. If possibly, try using IsPostback to only databind on the first page load.
C#
if(!IsPostBack)
{
rptPendingItems.DataBind();
}
VB
If Not IsPostBack Then
rptPendingItems.DataBind()
End If
If that's not possible, or doesn't work, you'll probably have to get and set all of those checkbox values mannually, and persist them against your data set, or in session or summat.
I had a repeater inside a user control on a page with other user controls which cause post backs. In some cases, I wanted to rebind on postback so I created a bool property (IsDirty) on the page that I could set to true when I wanted to rebind the data on postback. Then in my page_load, I checked if (!IsPostBack || IsDirty) before databinding.

populating a gridview with a button's click event

I have a page that has two dropdownlists(one for the locations, and the other for departments), an employee search textbox and a button. On the other page, I have a gridview. Now, what I want to achieve is that when a user types an employee's name in the textbox control, selects a location from the location dropdownlist, and a department from the departments dropdownlist, and click the button(search), the gridview on the other page must show the required information of a SINGLE employee. Only one row must show.
I have created a database for the employees. I know how to do this with the autopostback but i have not tried it using a button's click. NB: the gridview should show only one row of a selected employee. I'm using ASP.NET VB
Your help will high appreciated.
Try this
<asp:Button ID="srchButton" Text="BindData" runat="server" OnClick="BindData" />
<asp:GridView ID="GridView1" runat="server">
</asp:GridView>
protected void BindData(object sender, EventArgs e)
{
Gridview1.Datasource = YourDataSource;
GridView1.DataBind()
}
OK, cross-page postbacks in ASP.NET. Here we go.
Start with your search page, which we'll call search.aspx - this has your dropdownlists, textbox and button.
Employee Name: <asp:TextBox runat="server" ID="SearchTextBox" />
<br />
<asp:DropDownList runat="server" ID="LocationDropDownList">
<asp:ListItem Text="Springfield" Value="Springfield" />
<asp:ListItem Text="Shelbyville" Value="Shelbyville" />
</asp:DropDownList>
<br />
<asp:DropDownList runat="server" ID="DepartmentDropDownList">
<asp:ListItem Text="Nuclear Power" Value="Power" />
<asp:ListItem Text="Dr. Frink's Lab" Value="Research" />
<asp:ListItem Text="Mr. Burn's Office" Value="Management" />
</asp:DropDownList>
<br />
<asp:Button runat="server" ID="SearchButton" Text="Search" PostBackUrl="~/SearchResults.aspx" />
Note that the button has a PostBackUrl attribute - this is what posts the request off to the results page. We also need to change the search.aspx.designer.vb so that the dropdownlists and textbox are public properties, not protected.
Public WithEvents SearchTextBox As Global.System.Web.UI.WebControls.TextBox
The results page, which will be searchresults.aspx, has the GridView on it.
<asp:gridview runat="server" id="SearchResultsGridView" />
Now, how to handle the cross-page postback in the code. In the Page_Load event for searchresults.aspx, we check the PreviousPage property. PreviousPage could be Nothing (if, say, the user typed in searchresults.aspx directly), so if it is we'll redirect back to search.aspx. If PreviousPage is something, then we can check the IsCrossPagePostback property. If this is True, then we've probably got here from our search.aspx page (this may not be a completely valid assumption, but it's good enough for right now). If this is the case, then we can cast PreviousPage to the underlying class of search.aspx, and since we made the dropdownlist and textbox controls public, we can then access them as properties in our code here.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim employeeName As String
Dim department As String
Dim location As String
Dim searchPage As Search
If PreviousPage Is Nothing Then
Response.Redirect("search.aspx")
Else
If PreviousPage.IsCrossPagePostBack Then
searchPage = DirectCast(PreviousPage, Search)
employeeName = searchPage.SearchTextBox.Text
department = searchPage.DepartmentDropDownList.SelectedValue
location = searchPage.LocationDropDownList.SelectedValue
Call bindData(employeeName, department, location)
End If
End If
End Sub
Private Sub bindData(ByVal employeeName As String, ByVal locationName As String, ByVal departmentName As String)
With searchResultsGridView
.DataSource = 'Some code that passes the search parameters to the database
.DataBind()
End With
End Sub
As for your requirement that the search results should only show a single row, consider whether or not it is possible to have two employees with the same name, in the same department, in the same location. It might be unlikely, but I don't think it's impossible and I'm not sure you should have a restriction that you shouldn't show it. If this was, say, a payroll system, you could end up with a record you'd never be able to get to through the UI, so you'd never be able to stop paying that particular employee - probably not what you'd want!

Resources