asp.net/vb.net System.Web.UI.WebControls.RepeaterItemEventArgs question - asp.net

I'm really new to asp.net so please forgive me if this seems like a really basic question. I have an asp.net page that contains a repeater. Here's the code:
<div class="formRow">
<asp:Repeater ID="uxStudentFormActive" runat="server">
<ItemTemplate>
<span style="font-weight:bold;" ><asp:Literal ID="uxFormName" runat="server" Text="#" /></span><br />
<asp:TreeView ID="uxFormHistoryList" runat="server" Target="_blank" />
</ItemTemplate>
</asp:Repeater>
</div>
Here's the sub in my vb.net page that handles uxStudentFormActive.ItemDataBound:
Protected Sub uxStudentFormActive_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles uxStudentFormActive.ItemDataBound
Dim dr As DataRowView = CType(e.Item.DataItem(), DataRowView)
If Convert.ToInt32(dr("FormId")) = 29 Then
...
End If
End Sub
I'm not exactly sure how the aspx page interacts with the vb.net page. My question is how do I find out how where the values for e that are being passed to the sub uxStudentFormActive_ItemDataBound in my vb.net page are coming from? Thanks in advance.

From this MSDN article on handling events in ASP.Net:
Events [in ASP.Net] are based on the delegate model...A delegate is a type that holds a reference to a method... An event is a message sent by an object to signal the occurrence of an action. The action could be caused by user interaction, such as a button click, or it could be raised by some other program logic, such as changing a property’s value. The object that raises the event is called the event sender... Data that is associated with an event can be provided through an event data class.
In your case, the event data class is RepeaterItemEventArgs.
To respond to an event, you define an event handler method in the event receiver. This method must match the signature of the delegate for the event you are handling. In the event handler, you perform the actions that are required when the event is raised, such as collecting user input after the user clicks a button. To receive notifications when the event occurs, your event handler method must subscribe to the event.
Reading that, you might say "Well that's well and good, but what does it mean?" In your project, you probably have a property set at the top of your .aspx page named AutoEventWireup. It's probably set to true. This property does what it seems: it automatically wires up your events so that you don't have to. This is how your .aspx page knows how to interact with the code-behind file.
On your .aspx page, you have your repeater control. On your code-behind file, you have your event handler method. Because you have AutoEventWireup set to true, those two things are automatically linked together as long as your event handler method signature matches the signature of the delegate for that event. In this case, that event is ItemDataBound.
To your original question, where do the values of e come from? From the sender!
Protected Sub uxStudentFormActive_ItemDataBound(ByVal sender As Object, ByVal e As System.Web.UI.WebControls.RepeaterItemEventArgs) Handles uxStudentFormActive.ItemDataBound
In this method signature, you have two parameters: sender, and e. As described in the quote above, the sender is the object that raises the event. In your case, this is the RepeaterItem. Since the repeater likely contains many of these objects, the event can be raised multiple times. The event argument, e, is generated from the sender, or the RepeaterItem that was databound and caused the event to fire.
You can read more about the RepeaterItemEventArgs and the data available within on the MSDN.
As a side note, you can set AutoEventWireup to false and manually wireup the events as described in depth in the link to the MSDN article on the AutoEventWireup property.

Thanks to #Jack for giving me more insight into this. I'm sorry if my OP wasn't more clear, I did understand that the values were coming from the .aspx page, what I was actually asking is where the values that are being passed as e into my sub are being set, how e is being populated with data. The answer came from looking at the repeater id for the repeater I'm asking about, uxStudentFormActive. When I searched for this repeater id my vb.net code behind I found that the data source for the it was defined and bound in the Page_Load sub. Tracking this down lead me to a stored procedure in my database that is being passed session data and e is being set to the results of the stored procedure.

Related

NullReference on object in code behind after AsyncPostBack using UpdatePanel

I'm building a simple game in an ASP.NET/VB.NET web app. The game has a UI made up of several ImageButtons.
The web page's code behind file holds an instance to the game object which will manage each turn taken by players.
Everything worked when the Game object's methods were Shared.
The problem occurred after refactoring to make the game object work as an instance instead of a shared class. Now, when the action returns to the code behind, the instance of the game object is nothing.
I suspect that this has something to do with view state, but uh... Google hasn't helped.
The code bits:
Public Class _Default
Inherits System.Web.UI.Page
Private _gamePanel As Panel
Private _updatePanel as UpdatePanel
Private _game as Game
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
If Not Page.IsPostBack Then
'create a new instance of the game object on first loading page
_game = New Game(width, height, cellsToWin)
End If
' DisplayGameBoard() does the following:
' * Add images to the GameBoard panel inside of the GameBoardUpdatePanel
' * Attach click event handler to each image (addressOf located in this
' code behind file
' * DisplayGameBoard() works fine the first time but fails on
' subsequent post backs because there is no game object instance
Me.DisplayGameBoard()
End Sub
(From the page directive)
Language="vb"
AutoEventWireup="false"
CodeBehind="Default.aspx.vb"
Inherits="Game._Default"
ValidateRequest="false"
EnableEventValidation="false"
EnableViewState="true"
(update panel on the web page)
<asp:UpdatePanel ID="GameBoardUpdatePanel"
runat="server"
UpdateMode="Conditional"
RenderMode="Block"
EnableViewState="true"
ViewStateMode="Enabled"
ChildrenAsTriggers="true" >
<ContentTemplate>
<asp:Label ID="PlayerName"
runat="server"></asp:Label>
<asp:Panel ID="GameBoard"
runat="server"
cssclass="gameBoard"></asp:Panel>
</ContentTemplate>
</asp:UpdatePanel>
It's not ViewState, it's simply the life time of the _Default instance.
You create an instance of the Game class and store that as a member of the page, and expect that instance to survive. The problem is that the instance of the page doesn't survive.
Each request for the page will result in a new instance of the _Default class to be created, and when the response is created the instance is thrown away. The reference to the instance of the Game class that you have stored in the page is also thrown away, and you lose any way to access it.
If you want to keep the instance of the Game class, you can store it in the Session collection, which is user specific:
If Not Page.IsPostBack Then
'create a new instance of the game object on first loading page
_game = New Game(width, height, cellsToWin)
' store the reference in the user session
Session("game") = _game
Else
' get the reference back from the user session
_game = DirectCast(Session("game"), Game)
End If
However, you should be carful about how much you store in the user session. Normally objects that are created in a page are short lived (i.e. milliseconds), so they have a small impact on the server resources. Anything that you store in the user session will be extremely long lived in comparison. Consider how large the Game object is, and if you really need to keep the entire object, or if you can keep just the information needed to recreate it for each request.

How to sort databound control when datasource caching is on

The SqlDataSource.Selected event does not fire when SqlDataSource caching is enabled and the server loads data from cache.
I was using the selected method and SqlDataSourceSelectingEventArgs to sort my data, but it doesnt fire sometimes.
Anyone have any ideas on an alternate way to sort when data comes from cache?
Protected Sub sdsSupplies_Selecting(sender As Object, e As System.Web.UI.WebControls.SqlDataSourceSelectingEventArgs) Handles sdsSupplies.Selecting
e.Arguments.SortExpression = "SortedColumnID ASC"
End Sub
What happens if you intercept the DataBinding event?

Single event handler for multiple links/buttons on ASP.NET

I have a dropdown list that contains a collection of names. My entire names list is very large (over 2,000) so I would like to pair down the names in the drop down list to those starting with the same letter.
To do this I would like to have 26 links all on the same line, one for each letter in the alphabet ..
A|B|C|D|E|F|G|H|I|J|K|L|M|N|O|P|Q|R|S|T|U|V|W|X|Y|Z
The idea being that the user clicks on the letter they are interested in and the stored procedure that obtains the list of names is re-executed to only grab those names starting with the letter that was clicked and then the resulting dataset is rebound to the dropdown list.
What is vexing me is how to handle creating all the "Click Events" necessary to deal with the user "clicking" on a link. I could create 26 different event handlers, one for each link, but I have to believe there is a simpler way I am not seeing.
Form demonstration here is the click event for one link, the letter "A" ...
Protected Sub lnkLetterA_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkLeterA.Click
Call LoadNamesIntoDropDown("A")
End Sub
Is there a way to create one event handler that could handle all 26 links? Thank you.
P.S. C# or VB.NET examples are fine. I just happen to be using VB.NET in this case.
You can reuse the same click handler a simple example
protected void HandleLinkClick(object sender, EventArgs e)
{
HyperLink link = (HyperLink)sender;
LoadNamesIntoDropDown(link.Text);
}
However, there are loads of autocomplete style solutions you can use. A free one from MS
http://www.asp.net/ajax/ajaxcontroltoolkit/samples/autocomplete/autocomplete.aspx
Of course you can have one handler to rule them all. Just connect the Click event of all the links to the same method.
Do you create the links dynamically in code-behind, or have you created them in the designer? If it is done in the designer:
Select a link
In the property grid, switch to the event view
In the click event, select your event handler from the dropdown list
Repeat for all links
In the event handler, use the sender argument to examine which of the links that was clicked, and act accordingly.
As per your example use:
Protected Sub lnkLetter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkLeterA.Click, lnkLeterB.Click, lnkLeterC.Click //etc
Call LoadNamesIntoDropDown(CType(sender, LinkLabel).Text)
End Sub

How to use a viewstate'd object as a datasource for controls on a user control

I've got a listview on a control. Each row comprises a checkbox and another listview.
The outer listview is bound to a property on the control (via a method call, can't set a property as a SelectMethod on an ObjectDataSource it would appear) which is lazy loaded suchly:
Public ReadOnly Property ProductLineChargeDetails() As List(Of WebServiceProductLineChargeDetail)
Get
If ViewState("WSProductLineChargeDetails") Is Nothing Then
ViewState("WSProductLineChargeDetails") = GetWebServiceProductLineChargeDetails()
End If
Return DirectCast(ViewState("WSProductLineChargeDetails"), Global.System.Collections.Generic.List(Of Global.MI.Open.WebServiceProductLineChargeDetail))
End Get
End Property
The shape of the object referenced by the data source is something like this:
(psuedocode)
Product
{
bool Licenced;
List<Charge> charges;
}
Charge
{
int property1;
string property2;
bool property3
.
.
.
}
The reason for the use of viewstate is this:
When an one of the checkboxes on one of the outer list view rows is checked or unchecked I want to modify the object that the ODS represents (for example I'll add a couple of Charge objects to the relevant Product object) and then rebind.
The problem I'm getting is that after every postback (specifically after checking or unchecking one of the rows' checkbox) my viewstate is empty. Thiss means that any changes I make to my viewstate'd object is lost.
Now, I've worked out (after much googling and reading, amongst many others, Scott Mitchel's excellent bit on ViewState) that during initial databinding IsTrackingViewState is set to false. That means, I think, that assigning the return from GetWebServiceProductLineChargeDetails() to the ViewState item in my Property Get during the initial databind won't work.
Mind you, even when the IsTrackingViewState is true and I call the Property Get, come the next postback, the viewstate is empty.
So do you chaps have any ideas on how I keep the object referenced by the ObjectDataSource in ViewState between postbacks and update it and get those changes to stay in ViewState? This has been going on for a couple of days now and I'm getting fed up!
Cheers in advance
Steve
In order for changes to be tracked in the viewstate the object must be assigned to the viewstate when IsTrackingViewState is True. Viewstate starts tracking after Init in the pagelifecycle. You are probably binding too early for the objects to be stored in viewstate. You should bind the list view after the Init stage, probably in the load stage.
i.e.
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs)
ListView.DataSource = ProductLineChargeDetails
ListView.DataBind
End Sub

Why is the DataBind() method necessary?

Simple question, I guess.
For a long time I've blindly followed a (supposedly) common pattern when programmatically databinding my ASP.NET controls. Namely:
gridView1.DataSource = someList;
gridView1.DataBind();
However, if I were setting my GridView to bind to a DataSource control via the DataSourceID property, the call to DataBind() is unnecessary. Namely:
gridView1.DataSourceID = LinqDataSource1;
is sufficient.
Furthermore, if you try to set the DataSource property in ASPX markup, you are greeted with the following:
You cannot set the DataSource property declaratively.
I assume these are related, but I am still stumped as to why DataBind() is necessary. The difference between DataSource and DataSourceID is secondary - I can understand some magic taking place there. The real question is why doesn't the DataSource propery setter cause databinding automatically? Are there any scenarios in which we want to set the DataSource but not bind to it?
In ASP.Net, it's often important to have certain data available and ready at certain points in the page life cycle, and not before. For example, you may need to bind to a drop down list early to allow setting the selected index on that list later. Or you might want to wait a bit to bind that large grid to reduce the amount of time you hold that connection active/keep the data in memory.
Having you explicitly call the .DataBind() method makes it possible to support scenarios at both ends of the spectrum.
DataSource is a property of the BaseDataBoundControl class. DataSourceID is a property of the DataBoundControl class, which inherits from BaseDataBoundControl and did not exist before ASP.NET 2.0.
Since DataBoundControl is explicitly for displaying data in a list or tabular form, and BaseDataBoundControl cannot make that assumption, binding is not automatic when DataSource is set because the type of control may not match the structure of the data.
Of course, this is all just a guess based on the MSDN documentation, so I could be wrong.
I noticed that without using DataBind() that nothing will be displayed in my GridView so I always include it as shown in this section of code:
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
' TableAdapter object.
' Provide communication between this application and the database.
'-----------------------------------------------------------------
Dim suppliersAdapter As New SuppliersTableAdapter
' Get the data from the TableAdapter into the GridView.
'------------------------------------------------------
GridView1.DataSource = suppliersAdapter.GetSuppliers()
' Display the result set from the TableAdapter in the GridView.
'--------------------------------------------------------------
GridView1.DataBind()
End Sub
Please forgive the extra commenting as I'm also still learning ASP.Net as well and the comments will help me learn better "what and why" to use certain statements.
Try this:
if (GridView1.EditIndex == e.Row.RowIndex)
{
TextBox t2 = (TextBox)e.Row.FindControl("TextBox2");
DateTime dt2;
if (DateTime.TryParse(t2.Text, out dt2))
{
t2.Text = dt2.ToString("yyyy-MM-dd");
}
}

Resources