November 2007 - Posts

I've run across a few situations in which I wanted to animate a certain row in a GridView as a result of some client action.  The reason that this is a little tricky is that the AJAX Control Toolkit's Animation Extender needs to act on a certain Target Control (identified of course by the TargetControlID) and you can't point the target control as a specific grid view row (not that you would even want to).

Both methods I will discuss use the same actual animation code -- they just differ in the way in which the animation is called.  I'll begin with the common animation code, which flashes the row with a color change animation (basically a fading highlight).

function animateRow(affectedRow)
{
 //first save the existing row color so you can restore it after the animation is completed
 //you may have to do some post-processing to make sure the affectedRowColor is a hex value like #FFFFFF
 var affectedRowColor = affectedRow.style.backgroundColor;
 animation = new AjaxControlToolkit.Animation.ColorAnimation(affectedRow, 2, 32, "style", "backgroundColor", "#ffff99", affectedRowColor);
 animation.play();
} 

Basically the above code uses the AjaxControlToolkit Animation API to create a ColorAnimation that acts on the affected row, which will cause the entire row to highlight and then fade back to its original color.

The quick method for getting access to the affected row can be used when an element of that row initiates the animation (for example, click on an update button flashes the row that it is contained in).  The code would look something like this:

<asp:TemplateField HeaderText="Highlight My Row"> 
 <ItemTemplate> 
 <input type="button" value="Click Me" onclick="animateRow(this.parentNode.parentNode);" /> 
 </ItemTemplate> 
</asp:TemplateField> 

The onclick event of this template field button calls the above animateRow function and passes it's grandparent node (this.parentNode.parentNode).  Since the DOM tree has the element inside a <td/> which is inside a <tr/>, we know that the element's grandparent is the row to animate.

The second method involves giving each row a unique identifier during the handling of the rowCreated event.  The details will change depending on your implementation, but lets assume that you are using a GridView with a bound ID property (which is also a datakey).  Then you need to handle the rowCreated event and add an "id" attribute to each row:

protected void gv_RowCreated(object sender, GridViewRowEventArgs e) 
 { 
 GridView gview = (GridView)sender; 
 e.Row.Attributes.Add("id", gview.DataKeys[e.Row.RowIndex]["id"].ToString()); 
 } 

This will allow you to dynamically update any row by executing the following javascript:

var id = "idhere"; 
var affectedRow = $get(id); 
 
animateRow(affectedRow); 

With a few modifications you can get some pretty dynamic per-row animations while letting the AJAX Control Toolkit do all the heavy lifting.  Enjoy!

The ASP.NET AJAX Control Toolkit's Calendar (Click Here To See The CalendarExtender Control In Action) is a very nice control that allows you implement a client side dynamic calendar for date-picking functionality. One interesting feature is the ability to change the calendar from the default "days" mode (shows the days in one month) to "months" mode (showing all of the months in the current year) by clicking on the calendar title. Another click on the title will change the calendar into "years" mode, which shows 12 years at a time.

One feature that would be nice is the ability to start the calendar control in any of the desired modes ("days", "months", or "years") depending on the type of interaction with the calendar that is most appropriate. For example, a current project of mine requires entering employee hire dates -- which are almost always at least a few years old.

The following is some simple code that allows you to get the desired functionality (in this case, we switch to the "years" mode) by handling the Calendar's OnClientShown event.

Step 0 -- The initial Calendar control hooked up to a TextBox

<asp:TextBox ID="txtTitleLength" runat="server"></asp:TextBox>

<AjaxControlToolkit:CalendarExtender ID="calTitleLength" runat="server"

TargetControlID="txtTitleLength">

</AjaxControlToolkit:CalendarExtender>

 

Step 1 -- Add a callback to the OnClientShown event (here: "calendarShown")

<asp:TextBox ID="txtTitleLength" runat="server"></asp:TextBox>

<AjaxControlToolkit:CalendarExtender ID="calTitleLength" runat="server"

TargetControlID="txtTitleLength"

OnClientShown="calendarShown">

</AjaxControlToolkit:CalendarExtender>

Step 2 — Handle the OnClientShown event (which takes 2 parameters: "sender, e") and then call the calendar control’s _switchMode() method

function calendarShown(sender, e) { sender._switchMode("years"); }


That’s all there is to it! One note: you must call the switchMode() method in the OnClientShown event and not the OnClientShowing event for the effect to work properly.

I can across a problem today where I had to attach a PDF file that is stored on a network share to an outgoing email using ASP.NET 2.0. This is pretty simple to do, except in my case the PDF filename on the share has an obfuscated name while its original name (file.pdf) is stored in a database lookup table. Looking at the System.Net.Mail.Attachment constructors, you'll see that three take a string filename and three take a System.IO.Stream object to represent the file. The string filename constructors do not possess the ability (as far as I could see) to give the attached file a "friendly name", although one of the Stream constructors does. So what I ended up doing was opening the file with a non-locking FileStream object and then passing it to the mail attachment object, careful to close the stream when I was done. Pretty simple, but I couldn't find any sources using this method so I thought I'd write it down here (minus error handling code for clarity):

System.Net.Mail.MailMessage message =new System.Net.Mail.MailMessage("from@from.com", "to@to.com", "Subject", "My attachment has a friendly name");

//Open the filestream with non-locking read permission

System.IO.FileStream fileStream = new System.IO.FileStream("fileSystemName", System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.Read);

message.Attachments.Add(new System.Net.Mail.Attachment(fileStream, "friendlyName.pdf"));

fileStream.Close();

I recently ran into a situation where I wanted to render the contents of a user control either directly to the current HTML stream or to a file format like MS Word. Fortunately .NET has the 'LoadControl' function that takes the virtual path of a User Control and returns a Control object. In order to get the rendered output of a user control into an HTML32TextWriter, you can use the following code:

Control report;
 
StringBuilder sb = new StringBuilder();
StringWriter sw = new StringWriter(sb);
Html32TextWriter hw = new Html32TextWriter(sw);
 
report = LoadControl("WebUserControl.ascx");
report.RenderControl(hw);

One word of caution: When loading a Web User Control through the LoadControl() method, the normal page lifecycle events, such as Page_Init and Page_Load, are not called. To make up for this deficiency, you can cast the returned Control object to the User Control type and call any required methods directly from the object reference before rendering the control. For example, I created an IReportUserControl interface that defines a LoadReport() method, and which all report-type Web User Controls derive from. Then I can simply insert the following code in order to run the proper initialization logic:

report = LoadControl("WebUserControl.ascx"); 
 
((IReportUserControl)report).LoadReport(); //Initialize the control 
 
report.RenderControl(hw);
More Posts