Hiding/Manipulating Databound Items(转载www.aspalliance.com

80酷酷网    80kuku.com

  ASP.NET offers a powerful way to render information from a database or XML file: Databinding. However, sometimes you need to be able to perform the databinding for almost all of the items in the data source. Or perhaps you have some special formatting or secondary data that you need to use with each row in the data source, so that you need a little finer control over how the data is bound to the control. In these cases, you will typically need to handle the onItemDataBound event, which is fired for each item as it is bound to your control. This gives you a LOT of flexibility, but unfortunately the code is a little bit hairy. Hopefully, having an example will help! First of all, let me explain that this example is taken from a LIVE application: my Regular Expression Library over at my ASP.NET training website, ASPSmith.com. You can see it in action by clicking here. You'll see what it is doing in a moment.

For my Regular Expression Library, I had several things I needed to adjust beyond the default databinding that my DataGrid provided "out-of-the-box". Firstly, I had a user_id field in my data that I wanted to convert to a link to a user's email. Next, I wanted to limit how much of the Description field was displayed on the search results page, to avoid causing the page to get excessively long (since the Description field is a TEXT field in my database, and could therefore be many megabytes long). Lastly, I had an Edit link that allowed the owner of the regular expression to edit it, but I didn't want that to be visible except if the current user was the owner of the expression. Let's see how this was done. First, let's take a look at my (rather lengthy) Datagrid declaration. The important part is listed in red.

default.aspx excerpt <asp:DataGrid id="dgRegexp" runat="server" AutoGenerateColumns="False" BorderColor="Black" BorderWidth="1" PageSize="5" AllowPaging="True" AllowCustomPaging="True" OnPageIndexChanged="dgRegexp_PageIndexChanged" onItemDataBound="dgRegexp_ItemDataBound" GridLines="Horizontal" PagerStyle-Mode="NumericPages" PagerStyle-HorizontalAlign="Center" PagerStyle-Position="TopAndBottom" PagerStyle-Width="100%" HeaderStyle-BackColor="#CC0000" HeaderStyle-Font-Bold="True" HeaderStyle-Font-Name="Verdana" HeaderStyle-Font-Size="9pt" HeaderStyle-ForeColor="White" ItemStyle-Font-Name="Arial" ItemStyle-Font-Size="8pt" AlternatingItemStyle-BackColor="#DDDDDD">  

This event, onItemDataBound, is supported by any control that supports data binding. You can use it with DataGrids, DataLists, Repeaters, etc. In this case, I have mapped mine to the "dgRegexp_ItemDataBound" event handler, which we'll take a look at now:

default.aspx excerpt protected void dgRegexp_ItemDataBound(Object Sender, DataGridItemEventArgs e)
{
// For Items and AlternatingItems,
// convert userid to email link
// truncate description
// hide edit link if not owner
if(e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{
Trace.Write("ItemDataBound",e.Item.DataItem.GetType().ToString());

int user_id = Int32.Parse(((System.Data.Common.DbDataRecord)e.Item.DataItem)["user_id"].ToString());
Trace.Write("ItemDataBound", "user_id: " + user_id.ToString());

ASPAlliance.DAL.UserDetails objUser = ASPAlliance.DAL.User.getUserDetails(user_id);
((System.Web.UI.WebControls.HyperLink)e.Item.FindControl("myuser")).Text =
objUser.first_name + " " + objUser.last_name + " (" + objUser.email + ")";
((System.Web.UI.WebControls.HyperLink)e.Item.FindControl("myuser")).NavigateUrl = "mailto:" + objUser.email;
Trace.Write("ItemDataBound", "myuser.Text: " + ((System.Web.UI.WebControls.HyperLink)e.Item.FindControl("myuser")).Text);

String desc = ((System.Data.Common.DbDataRecord)e.Item.DataItem)["description"].ToString();
if(desc.Length > 100)
{desc = desc.Substring(0,99);
desc += "...";
}
((System.Web.UI.WebControls.Label)e.Item.FindControl("description")).Text = desc;
ASPAlliance.DAL.Security sec = new ASPAlliance.DAL.Security(this.Request);
if((sec.user_id == 0) || (sec.user_id != user_id) || (!sec.isAuthenticated))
{
((System.Web.UI.HtmlControls.HtmlTableCell)e.Item.FindControl("editTD")).Visible = false;
}}}}


Ok, now that's what I call an example! None of that wussy little "just for demonstration" three lines of code stuff for us. No, we're going to go all out and show you something big and ugly that actually sits on a production site. But don't fear, it will all be clear to you in a moment, if it isn't already (even if you only know VB). Let's break this down.

The first 6 lines declare our method and throw in some comments. As I said, I basically have three things I want to do here:

Convert userid to an email link
Truncate the Description field
Hide the Edit link if current user is not the owner
The only thing you really need to watch here is to make sure that your second parameter's type is correct for the control you are using. This is pretty self-explanatory, but if you can't figure it out, you can always look at the definition of the particular control you are using in the Class Browser. For you VB.NET users, just convert "//" to a single quote, get rid of the { and switch the parameters to the type is following the name and has "As" in front of it.

Next, we need to make sure we're dealing with the correct item type. Since this event is raised for every item in the bound control, including Items, AlternatingItems, Separators, Headers, Footers, etc. ( complete list), we need to specify which kinds of items we are concerned with. In this case, we just want to deal with the main section of the control, so we check to make sure the item in question is either an Item or an AlternatingItem. This is handled by the if statement. We get the current item from our input parameter, e, and compare it to the ItemTypes we are concerned with. For you VB guys, || means "Or".

Note: I neglected to use alternating items when I first wrote this application, so the user's email was displayed for every other item, but the user's ID was displayed for the others!

Ok, now I've got some Tracing in place to help me with debugging. This just outputs the type of the current Item, and lets me verify that it is in fact either an Item or an AlternatingItem. You can leave this out of your implementation.

Next I grab the user_id. This is one ugly piece of code. Let me repeat it here and go through it piece by piece:
int user_id = Int32.Parse( ((System.Data.Common.DbDataRecord)e.Item.DataItem)["user_id"].ToString()); Let's start with the innermost parentheses, in red. This is C#'s method of Type Casting, and is necessary to convert the current DataItem to the DbDataRecord type. The orange set of parentheses completes this operation. For all intents and purposes, the contents of the orange parentheses are considered to be a DbDataRecord. Moving on to the green, this allows us to then reference the "user_id" element of this record, using C#'s array/collection syntax (in VB this would use () instead of []), and convert the contents to a String, because that is what Int32.Parse expects. Finally moving out to the black, Int32.Parse converts a String into an int. The results of this conversion are then stored in my user_id variable of type int. On the next line I have some more diagnostic code to output the user_id to the Trace log.

Ok, so now we have a user_id. The next chunk of code uses some custom controls that I wrote to handle my Users. The control is modelled after the ones found in the IBuySpy Application. In this case, I UserDetails class that holds my user's name and email address by calling the getUserDetails method of my User class. The next line is another hairy one, though:
( (System.Web.UI.WebControls.HyperLink)e.Item.FindControl("myuser")).Text = objUser.first_name + " " + objUser.last_name + " (" + objUser.email + ")";
Again, starting from the middle most parens, we have another typecasting operation being done. The red code is used to convert the orange code into a HyperLink. The orange code is used to find the control whose ID is "myuser" within the current item. In my template for my column in my datagrid, I have an <asp:HyperLink id="myuser"/> tag that this code refers to. The rest of this block of code sets the text of this hyperlink to the user's name and email address. The hyperlink tag looks like this in my DataGrid: <asp:hyperlink ID="myuser" Runat="server"> <%# DataBinder.Eval(Container.DataItem, "user_id") %> </asp:hyperlink>  


By now this typecasting is getting to be old hat. The next line pretty much does the same stuff as the previous line, but in this case we're setting the NavigateUrl property of our HyperLink to "mailto:" and the user's email address. Once again this is followed by some more diagnostic tracing.
((System.Web.UI.WebControls.HyperLink)e.Item.FindControl("myuser")).NavigateUrl = "mailto:" + objUser.email;

That's it for the email. Task 1 is complete. Now we want to truncate the description if it is too long. We do this using similar techniques. First, we grab the "description" from the current DataItem after converting it to a DbDataRecord type. Then we convert it to a string and assign it to a variable, desc (all in one line). Next, we check to see if its length is more than 100, and if it is, we convert it to just the left 100 characters (using Substring -- in VB we would have used Left()) and tack on a "..." to the end to show the users that there is more text. Finally, we use the FindControl syntax once more to locate the description Label control within our template, and set its Text property to the result.

That's 2 tasks down. One to go. This is the most commonly asked for feature of DataGrids and DataLists: how to hide a particular row or item within a databound list. In this case, I use my custom Security control to determine if the user is the owner of the current regular expression. If they aren't, or if they aren't logged in and Authenticated, then I set the table cell holding my Edit tag's Visible property to false. In order to do this, I had to make my table cell an HtmlControl by adding runat="server" to it and giving it an ID. I named the table cell "editTD", and I can use FindControl to locate the cell within my Item and access its properties. The cell itself is listed here: <td align="right" valign="top" id="editTD" runat="server">
[<a href='Edit.aspx?regexp_id=<%# Server.UrlEncode(DataBinder.Eval(Container.DataItem, "regexp_id").ToString()) %>'
title="Click to edit.">Edit</a>]
</td>  
That's all there is too it. For most people, they want to know how to hide something if its value is null. Just do the same thing I'm doing here, but replace the if statement that is referring to security with one that checks the value of the variable. You will probably need to use the (System.Data.Common.DbDataRecord)e.Item.DataItem) syntax described earlier to access your data and check it for null, but that's all there is to it.

Summary
Manipulating or hiding individual elements of a databound list or grid is not very difficult once you know a few tricks. However, the code IS pretty darned ugly. The code on this page works, and that is the best thing that can be said of any example. You can see it in action at ASPSmith Regular Expression Library. If you have trouble getting this to work with your own, I suggest that you first compare you code with mine, and if that doesn't yield any insight, ask the ASP.NET Data experts on the ASPNG Data Listserv. Be sure to include your failing code in your question.

分享到
  • 微信分享
  • 新浪微博
  • QQ好友
  • QQ空间
点击: