Archive

Archive for the ‘AJAX’ Category

WebGallery 2.0 – Introduction

February 19, 2008 4 comments

Over a year ago, I started creating the original “Photo Gallery,” which became the blueprint for my online photo and file repository.  I created the site because commercial solutions, like Flickr and SkyDrive, couldn’t provide me with exact URLs of both thumbnailed and full-size objects.  Google’s Picasa got close, but still required using their interface—which REALLY annoyed me if I wanted to post up photos for the blog.

With a year of experience behind me, and seeing what I liked/disliked about how WebStorage (its eventual name) worked, I set out to create version 2.0.

WebStorage2 FrontPage

Download Code: UPDATED 3 march 2008: build 38

Changes in this version:

  • Built on .NET 3.5.
  • Fully XHTML 1.1 compliant.
  • Compatible (mostly) and tested with with FireFox (2, 3pr), IE (6, 7), Opera (9.5), and Safari (3.0.4).
  • Removed Enterprise Library dependencies in favor of LINQ-to-SQL.
  • Resolution of file handing “issues” in v1.0.
  • Implementation of ASP.NET AJAX to speed up gallery rendering.
  • Added “paging” to the galleries.
  • Removed ASP.NET user controls in favor of cleaner ListViews.
  • Added caching to the WebStorageHandler.
  • Added Deflate and GZip HTTP Compression to the .aspx and .ashx pages.
  • Reengineered thumbnail managed (pre-fab’ed now) to speed up load times. (Thanks for the idea, Michael!)
  • and more!

Over the next few blog posts, I’m going to touch on each of the changes (noted above) and the reasoning behind them; however, I wanted to get the code out there.

Project LayoutProject Layout

The project’s laid out in a simply hierarchy—a folder per respective “area,” including the LINQ-to-SQL models.  I build the project in such a way to, I hope, easily move into the MVC frameworkThe additional App_Browsers directory is used by our CSS Friendly adapters.

This project is based on ASP.NET 3.5 (without the 3.6 extensions) and a couple of additional libraries:

I also used Visual Studio 2008’s new web tests (seen in the screenshot) to complete load testing and tidy up code.  I haven’t included that in the source code, but I plan to do a post on the features and results—it’s a very slick system.

Data Model

With full LINQ-to-SQL support, I opted for LINQ as a solution rather than the Enterprise Library.  LINQ encapsulates the SQL logic to keep our code secure, the data context object is a partial class—allowing us to custom code methods and properties into our models, and it just “works.”  If you haven’t noticed from other posts of mine, I really like LINQ as an ORM solution—especially now that it’s built into the environment and fully supported by the framework.

The model itself is quite simple.  Three tables control a majority of the functionality for the application.

The WebFile table
The WebFile table contains the actual objects for our WebStorage gallery.  ObjectBody and ObjectThumbnail are image columns containing the binary information stored for our objects.  The rest of the columns are attributes providing either end-user information (such as Description) or rendering information (such as ObjectType). 

A change from the previous data model is that thumbnails are stored along with the web files and are not “automagically” generated—saving both computation time on the server and speeding up rendering for the client.

For our two image fields, I’ve also enabled “lazy loading” or “delay loading”—an attribute that only returns these fields if they are explicitly used within the code and only once per query to save bandwidth.

The ContentType table
The ContentType table manages the MIME types, their thumbnails, and matching object types.  This table is used to render icons for PDFs, RARs, ZIPs, and other file types as well as generic icons for photos that do not have thumbnails.

The Gallery table
The Gallery table contains the keys, names, and allowed roles for each gallery.  The roles match up to membership roles provided by ASP.NET’s Configuration.

Next…

In the next post, I’ll discuss what went into the LINQ-to-SQL queries and how the use of the DataContext’s partial classes sped up development.  I’ll also discuss how the ImageHandler has been updated to match these data changes.

Edit: Updated to fix the fonts… I should know better than to create it in Word and then just copy/paste. :(

Migrating to a new Web Gallery

February 5, 2008 Comments off

I’m currently migrating to a new version of Web Gallery (code and such coming soon); so photos may be a bit screwy the next few hours. :) Thanks for understanding.

[Update: Everything’s up and running! 

Over the next couple of days, I’ll post up the code for the new v2.0 of the Web Gallery project as well as a quick walkthrough of what changed.  I’m still finishing the admin areas, but the “user” side of the site is up and operational.

http://photos.tiredstudent.com]

New Articles Section and AJAXing in .NET Article

January 11, 2008 7 comments

Last year, I had several requests to take my “longer” blog posts and series and make articles out of them.  I understand where readers are coming from and empathize—reading 4–5 posts that are 2–3 pages long across a week of entries can be… very disconnected.  In addition, code formatting, images, and such are difficult to get exactly right on a blog image (I tend to avoid capturing code in images so that it’s still searchable).

So, to that, I’ve added a new section to the blog, Articles.

In this, I’ll tend to focus on using the blog for short bits of information, key points, and summaries of various topics.  The Articles section will be for the longer, in-depth reviews of technologies, practices, and guides.

The first post in this section is from the recent AJAXing in .NET series

AJAXing in .NET – #3 – Live Volta and Script#

January 8, 2008 Comments off

This is the third and final part of the series looking at several “AJAXing” technologies for .NET—ranging from “old school” JavaScript to new, VERY alpha technologies like Volta.

Post 1:

  • Example #1 – Plain ASP.NET Page with PostBacks
  • Example #2 – ASP.NET AJAX with UpdatePanels

Post 2:

  • Example #3 – Standard HTML and JavaScript
  • Example #4 – ASP.NET AJAX Framework and JavaScript

Post 3 (this post):

  • Example #5 – Nikhil Kothari’s Script#
  • Example #6 – Microsoft Labs Live Volta

This post, to be totally honest, will be short.  Why?  After FAR too long of dinking with them, I simply can’t get either solution to work.  Here’s where I’m at NOW.  Once I get these working, I’ll better evaluate them against current JavaScript solutions.  That said, the sheer idea of learning a language to avoid writing a language seems odd at best…

#4. Microsoft Live Labs Volta

I previewed Microsoft Live Labs Voltron Volta back in December and was quite impressed—a Microsoft-designed solution for creating type-safe JavaScript within C#.  I wasn’t thrilled with the special project layouts or 45K of compiled Volta code that attached to each project; however, it’s in … alpha, I expected that.

In our Volta code-behind, we have the following logic. 

public partial class VoltaPage1 : Page

{

 

Select photoList;

Image photoPreview;

 

public VoltaPage1()

{

InitializeComponent();

photoList.Change +=

new HtmlEventHandler(photoList_Change);

}

 

void photoList_Change()

{

photoPreview.Style.Display = “block”;

       photoPreview.Src =  “Images/” + photoList.Value;

}

 

partial void InitializeComponent()

{

photoList =

Document.GetById<Select>(“PhotoList”);

photoPreview =

Document.GetById<Image>(“PhotoPreview”);

}

}

That compiles, is easy to read, and type safe.  Neato.  The HTML code is identical to our prior examples, so a simple copy and paste from there.  That saves some time.

The problem?

It appears that Volta doesn’t appreciate resources that are not embedded.  I’ve posted up to the Volta community groups and will slowly work through either a) rectifying what the correct code should be or b) accepting that this is “outside the scope” of the current Volta design.  I can’t fathom having hundreds of embedded resources in a project—for simple graphics.

Finally, it appears the problem that Henry discussed in my last post also exists in Volta—Document.GetById isn’t case sensitive at all. :(  Thanks Henry for the heads-up to keep that in mind!

[Update: 10 January 2008 : Danny van Velzen’s explaination in the forums helped out a lot.  At this time, as expected, the CTP simply doesn’t support anything besides embedded resources; however, has logged the request as a future work item.  *cheer*  To work around this problem, he recommended a post-build event, which is basically a batch command.  I’ve tried that out and this example works like a champ!

The only gotcha is figuring out where to copy the files to and what correlates to the “root” of your application.  It’s not the root of our bin\Debug or bin\Output.  It’s the Volta directory underneath.  With that information, you can write up a quick event:

xcopy /i /y “$(ProjectDir)Images” “$(TargetDir)Volta\Images”

Given this simply copies the images for this prototype project; however, you could use these events to copy pages, .css, or anything that you didn’t feel like “embedding” into your project.  As I noted on the Volta communities post—I’m looking forward to this maturing and having this functionality built into the compiler. :)

With this updated information, I can finally compare implementation with our other options..

  • HTML Code: 9, Code Behind: 5 with whitespace and method names.
  • To me, this code is just as simple to read as JavaScript—maybe a bit easier because it’s strongly typed and hooks up event handlers just like .NET code.
  • All tests come back clean—and Volta supports FireFox debugging out-of-the-box, which is great because I have come to prefer FireBug over the IE Developer Toolbar.
  • Pitfalls are, at this time, the fact it’s VERY alpha and still in development.  Most of the DOM appears to be ready to go, however, issues like the embedded resources make this impractical for production use at this time.  In addition, Volta requires a special project type for its tier-splitting—you can’t just drop some Volta/JavaScript into a project and go.  That’s a HUGE drawback to me.  I’d love to see the technology integrated into the existing web platform so I could program JavaScript like this against Web Forms, MVC, or whatever.

#5. Script# 0.4.5.0

The latest build of Script#, 0.4.5.0, appears to have a few glitches in the Scriptlet editor (cutting out the top and bottom lines, throwing compile errors when they don’t exist, etc) and after blowing through about a dozen project—it just won’t compile.  Period. 

Here’s the code for the class.  It looks right, from what I have as examples, but blows up that I have extra “}” (which is a known bug apparently) and believes that my IDisposable doesn’t exist, though I see it right there. :(

using System;

using System.DHTML;

using ScriptFX;

using ScriptFX.UI;

 

public class Viewer : IDisposable

{

    private SelectElement _photoList;

    private ImageElement _photoPreview;

    private DOMEventHandler _photoListOnChangeHandler;

 

    public Viewer()

    {

        _photoListOnChangeHandler =

new DOMEventHandler(PhotoListOnChange);

        _photoList =

(SelectElement)Document.GetElementById(“PhotoList”);

        _photoList.AttachEvent(“onchange”, _photoListOnChangeHandler);

    }

 

    public void PhotoListOnChange()

    {

        _photoList =

(SelectElement)Document.GetElementById(“PhotoList”);

        _photoPreview =

(ImageElement)Document.GetElementById(“PhotoPreview”);

 

        _photoPreview.Src = “Images/” + _photoList.Value;

    }

 

    public void Dispose()

    {

        if (_photoListOnChangeHandler != null)

        {

            _photoList =

(SelectElement)Document.GetElementById(“PhotoList”);

            _photoList.DetachEvent(“onchange”, _photoListOnChangeHandler);

 

            _photoListOnChangeHandler = null;

        }

    }

}

I’m going to keep working with it (because the prototypes I have gotten working have worked well, but also don’t seem to work under 0.4.5.0) and I’ll update this post when I have more information.  If anyone out there is a Script# expert and has 0.4.5.0 up and going with VS2008, email me, please. :).

AJAXing in .NET – #2 – Pure JavaScript and AJAX Framework JavaScript

January 7, 2008 7 comments

This is the second in the three part series looking at “AJAXing” technologies for .NET developers.

Post 1:

  • Example #1 – Plain ASP.NET Page with PostBacks
  • Example #2 – ASP.NET AJAX with UpdatePanels

Post 2 (this post):

  • Example #3 – Standard HTML and JavaScript
  • Example #4 – ASP.NET AJAX Framework and JavaScript

Post 3 (this post):

  • Example #5 – Nikhil Kothari’s Script#
  • Example #6 – Microsoft Labs Live Volta

In these two examples, we’ll take a look at the differences of JavaScript programming—between “standard” JavaScript and using the methods and objects provided by the ASP.NET AJAX Framework, but without using the actual server-side controls.

#3. Standard HTML and JavaScript

The next example is a classic—clean HTML and a JavaScript function.  This is a standard HTML page without any “fancy” .NET or framework technologies.  How does this compare to .NET?

In our header, there’s a simple JavaScript function to handle the OnChange event of the drop down list:

<script type=”text/javascript” language=”javascript”>

function LoadPhoto()

{

PhotoPreview.style.display = ‘block’;

       PhotoPreview.src = Images/ + PhotoList.value;

}

</script>

Next, our HTML.

<select id=”PhotoList” onchange=”LoadPhoto()”>

<option label=”ABCs – Blocks” value=”abc_blocks.jpg” />

       <option label=”ABCs – Chalkboard #1″ value=”abc_board.jpg” />

       <option label=”ABCs – Chalkboard #2″ value=”abc_board2.jpg” />

       <option label=”Graduation” value=”capandgown.jpg” />

</select>

<br /><br />

<img id=”PhotoPreview” style=”display: none; src=”” />

As we can see from the Fiddler capture, the HTML, of course, is EXTREMELY thin here and, since postback events are not firing, the page ever reloads, simply loads the resources (in this case, images) as necessary.  In addition, the images are cached, so additional downloading isn’t necessary..

  1. HTML Code: 8 + 2 4 JavaScript function lines (see below).
  2. I may be a bit older, but this is how it “used” to be done, so it’s readable to me.  For those unfamiliar with JavaScript may be turned off by it.
  3. IE 7 and Safari (*shocked*) work, however, Opera and FireFox are broken.  See details below.
  4. As you’ll read below, managing compatibility between JavaScript functionality on each platform is a HASSLE and can be a major turn off for DIY JavaScript AJAX.

Details for Compatibility Issues:

IE 7 and Safari actually render correctly because they use the “label” property from HTML 4.0 for option boxes.  FireFox and Opera turn out blank.  To have options in those browsers, we’ll need to place the text in the body of the tag. 

<option label=”ABCs – Blocks” value=”abc_blocks.jpg”>
ABCs – Blocks
</option>

That fixes Opera, but FireFox is still broken.  Why?  Because FireFox can’t read the DOM directly, you have to populate each element into a variable and manipulate the variable.  Updating our JavaScript to the following code will fix the problem.  Also, since this method works in all the OTHER browsers, this would be the “preferred” method to accomplish this.

var photoPreview = document.getElementById(‘PhotoPreview’);

var photoList = document.getElementById(‘PhotoList’);

 

photoPreview.style.display = ‘block’;

photoPreview.src = ‘Images/’ + photoList.value;

While this code works, you can run into challenges for browsers that do not yet support getElementById.

#4. ASP.NET AJAX Framework and JavaScript

In our last example, browser compatibility was the most challenging pitfall to overcome.  If we want to write our own JavaScript, but would like the padding of a framework, we can use the ASP.NET AJAX framework without all the fancy server-side controls.

When we add a new AJAX Web Form, a single control is added, the ScriptManager.  In this example, we’re not going to use UpdatePanels, but simply access the objects provided for us by the ScriptManager.

The JavaScript in our Header:

<script type=”text/javascript”>     

function LoadPhoto() {    

       $get(‘PhotoPreview’).style.display = ‘block’;

       $get(‘PhotoPreview’).src = ‘Images/’ + $get(‘PhotoList’).value;

}

</script>

And the HTML:

<asp:ScriptManager ID=”ScriptManager1″ runat=”server” />

<select id=”PhotoList” onchange=”LoadPhoto()”>

<option label=”ABCs – Blocks” value=”abc_blocks.jpg”>

              ABCs – Blocks</option>

<option label=”ABCs – Chalkboard #1″ value=”abc_board.jpg”>

              ABCs – Chalkboard #1</option>

<option label=”ABCs – Chalkboard #2″ value=”abc_board2.jpg”>

              ABCs – Chalkboard #2</option>

<option label=”Graduation” value=”capandgown.jpg”>

              Graduation</option>

</select>

<br /><br />

<img id=”PhotoPreview” style=”display: none; src=”” />

The $get alias simply returns browser-compatible JavaScript for getElementById.  You can read more about how this alias works on Irena Kennedv’s blog.  The short is that this alias will generate the correct code based on the browser.

The Fiddler logs are nearly identical to the plain JavaScript; however, the .aspx page is a bit heavier.

  1. HTML Code: 9 + 2 JavaScript function lines.
  2. Aside from familiarization with the aliases and framework functions in JavaScript, this code is nearly identical to the
  3. The only difference at this point is that the code allows us to access the $get alias and, most importantly, cross-browser compatibility handled by the framework—not you.
  4. Past the bit of losing “update panels”, this is a nice middle ground between pure JavaScript and pure server-side AJAX Framework.

This methodology also has another benefit: you can directly access web services (.asmx) from your JavaScript client code.  For more information on this topic, read Calling Web Services from Client Script.  I haven’t done a lot with this yet, but have a few notes sitting around to give it a try and see how it compares when reading actual data across the wire.

AJAXing in .NET – #1 – Plain ASP.NET and ASP.NET AJAX

January 7, 2008 2 comments

With the release of Microsoft Live Labs Volta, Nikhil Kothari’s recent update of Script# to support VS 2008, the ASP.NET AJAX Library’s new functionalities, and good ‘ol JavaScript—developers are not limited on AJAX solutions for the Microsoft platform.  Given, JavaScript can be on any platform, I tend to focus more on .NET solutions. :)

One of my holiday projects was to weigh and see exactly what went back and forth across the wire for each of these technologies and compare that to:

  • Implementation lines of code,
    • I don’t count using statements, headers, and “required” coding lines, simply those lines that implement the solution.
  • Intuititiveness of code,
    • Does the code make sense to write?
  • Browser support,
    • Does it work and look the same on IE 7.0, FireFox 2.0, Opera, and Safari?
  • Weight of transmissions (using Fiddler).
    • How much data is going across the line for comparable transactions?
  • Pitfalls?
    • What are the gotchas?

Download Source Code : Download Project Solutions (coming soon)

Note: This project contains two solutions, one for Volta project and one for all the others.

To make this a bit easier to read (and to write :) ), I’ve broken the content into a series of posts.

Post 1 (this post):

  • Example #1 – Plain ASP.NET Page with PostBacks – Seeing our prototype page with standard ASP.NET—no AJAX.  This will provide our baseline.
  • Example #2 – ASP.NET AJAX with UpdatePanels – The “default” implementation of the ASP.NET AJAX Framework—using UpdatePanels to manage partial rendering with “postbacks” still happening in the background.

Post 2:

  • Example #3 – Standard HTML and JavaScript – This is the “old” way to do things: directly manipulating the DOM.
  • Example #4 – ASP.NET AJAX Framework and JavaScript – Manipulating the DOM using the aliases and cross-browser compatibility features of the AJAX Framework.

Post 3:

  • Example #5 – Nikhil Kothari’s Script# – Script# is a scripting solution that sits on top of the C# development environment.
  • Example #6 – Microsoft Labs Live Volta – Previewed before, we’ll build the same example as the rest of the examples in Volta for comparison.

Now, let’s get started!

#1. Plain ASP.NET Page – Postbacks

Moving into .Net, let’s start with a simple ASP.NET page—no AJAX involved.  This page has a drop down list (PhotoList) and an image control (PhotoPreview)—populating the image control OnChange of the drop down list.

<asp:DropDownList ID=”PhotoList” runat=”server” AutoPostBack=”true”

OnSelectedIndexChanged=”PhotoList_SelectedIndexChanged”>

<asp:ListItem Text=”ABCs – Blocks” Value=”abc_blocks.jpg” />

<asp:ListItem Text=”ABCs – Chalkboard #1″ Value=”abc_board.jpg” />

<asp:ListItem Text=”ABCs – Chalkboard #2″ Value=”abc_board2.jpg” />

<asp:ListItem Text=”Graduation” Value=”capandgown.jpg” />

</asp:DropDownList>

<br /><br />

<asp:Image ID=”PhotoPreview” runat=”server” Visible=”false” />

In our code behind:

protected void PhotoList_SelectedIndexChanged(object sender, EventArgs e)

{

PhotoPreview.ImageUrl = “~/Images/” + PhotoList.SelectedValue;

       PhotoPreview.Visible = true;

}

Using Fiddler, an HTTP debugging tool, we can see that each time the page is requested, it posts back and grabs the image.  It’s also important to note that there isn’t any caching at this point.  Notice how events #39 and #43 request the same image and transmit it.

Using our scale above:

  • HTML Code: 9, Code Behind: 2
  • Being standard HTML and .NET code-behind, this is easily readable and makes sense. 
  • As we can see from the image below, the page looks much the same on every browser (given, it’s pretty basic).  The browsers, clockwise from top-left, are: Safari b3, IE 7, Opera 9, and FireFox 2.
  • Avoid postback “flash” is the most common, I think, to implement some sort of AJAX technology—cleaning up a UI and improving the user experience.  The lack of caching (with the post back) is also a trouble; however, caching could be implemented with additional coding.

#2. ASP.NET AJAX with UpdatePanel

Our first method would be the standard ASP.NET AJAX technique—surrounding those two controls with an UpdatePanel and adding a ScriptManager to the page.

<asp:ScriptManager ID=”ScriptManager” runat=”server” />

<asp:UpdatePanel ID=”UpdatePanel” runat=”server”

UpdateMode=”Conditional”>

<ContentTemplate>

<asp:DropDownList ID=”PhotoList” runat=”server”

AutoPostBack=”true”

OnSelectedIndexChanged=”PhotoList_SelectedIndexChanged”>

<asp:ListItem Text=”ABCs – Blocks” Value=”abc_blocks.jpg” />

<asp:ListItem Text=”ABCs – Chalkboard #1″ Value=”abc_board.jpg” />

<asp:ListItem Text=”ABCs – Chalkboard #2″ Value=”abc_board2.jpg” />

<asp:ListItem Text=”Graduation” Value=”capandgown.jpg” />

</asp:DropDownList>

<br /><br />

<asp:Image ID=”PhotoPreview” runat=”server” Visible=”false” />

</ContentTemplate>

</asp:UpdatePanel>

While our UI hasn’t changed, our HTTP traffic has changed quite a bit.  Here we can see the WebResource and ScriptResource files pull down to the local client and cache as well as the first load of the page.  What is interesting here is that on request #89, I’ve rerequested the capandgown.jpg image, but it never re-requests it, the cached image just loads on the client.  Good deal and MUCH faster.

Using our scale above:

  • HTML Code: 14, Code Behind: 2
  • This is the basic way of implementing the ASP.NET AJAX Framework—enclosing existing controls in panels and letting partial rendering do it’s magic.  I see this as very intuitive syntax.
  • Functionality is identical on all four platforms; this is because the ASP.NET AJAX framework handles browser support for us via ScriptManager.
  • As you can see from the Fiddler log, this page is extremely heavy—trading off smooth performance during usage for a resource load at the page load.

AJAX 1.0 Templates for VS2008 – Now multitargeting works!

December 20, 2007 Comments off

One of the most painful transitions to VS2008 was creating new AJAX 1.0 sites.  Even through VS2008 claimed multitargeting out of the box, the RTM didn’t include the templates needed to target AJAX 1.0 sites.

ASP AJAX 1.0 Template in VS 2008Well, that’s changed! 

The new templates add both web site and web application templates and work great—it’ll be nice not to hack my projects’ web.config files up before I even start. ;)

 

 

Brad Abrams wrote:

Today we released ASP.NET 2.0 AJAX Templates for VS2008.  This release contains project templates for using Visual Studio 2008 or Visual Web Developer 2008 to create new web sites and web applications with ASP.NET AJAX Extensions features. The project templates contain specific references to assemblies in .NET Framework 2.0 and ASP.NET 2.0 AJAX Extensions 1.0.

Download the ASP.NET 2.0 AJAX Templates for VS2008!

To try these out, make sure you have ASP.NET AJAX Extensions installed, then install the ASP.NET AJAX Templates for Visual Studio 2008.  

 

Behind the Scenes – ModalPopupTemplate

November 8, 2007 3 comments

The ModalPopupTemplate control is a Composite Control—or a control that is a collection of other controls and implements the CreateChildControls method.

This post demonstrates how the ModalPopupTemplate (MPT) was created and also points out a few of its current weaknesses and areas for improvement (hey, I’m honest…).

Attaching Custom Events

As with any control, the MPT has an array of external properties available.  Most importantly are the three events and the styling properties.

To attach custom events to a control, they are implemented similar to a property; however, the method used to attach the event is a virtual method.  Let’s take a look at our OkClick event.  The other events follow suit in functionality.

// Events of Popup

public event EventHandler OkClick;

protected virtual void OnOkClick(EventArgs e)

{

if (OkClick != null)

       {

              OkClick(this, e);

}

}

Our OkClick accepts EventHandler events and can be used for UpdatePanel triggers, etc; however, our control needs action methods (On_) to link events to methods on your page.  That’s where the virtual method comes in.

Later in the code, when the Ok, Close, and Cancel buttons are generated, there’s one more bit of code.  The Click events are optional so we still need to tie a bit of functionality to them to close the popup window.  This is done by mixing a bit of JavaScript into the mix.

if (OkClick != null)

{

// If an OK Behavior is assigned, use it.

       okButton.Click += OkClick;

}

else

{

// If not, the OK button just hides the popup.

       okButton.OnClientClick = “$find(‘popup’).hide(); return false;”;

}

Prefabricated Style Sheets and Custom Style Sheets

A template has to have a few styles built into it.  This is currently an “under construction” area of the control as there has to be a way to generic it up a bit and lose the ugly case statements.

When the DefaultStyle property is set to Custom, this code is bypassed or simply there isn’t a “style” attached to the control.  You’ll get plain black text, white background, and no borders.  If DefaultStyle isn’t specified in the control, the YUI theme is applied.

if (DefaultStyle != PopupStyle.Custom)

{

string includeLocation = “”;

switch (DefaultStyle)

{

case PopupStyle.YUI:

       includeLocation =

       Page.ClientScript.GetWebResourceUrl(this.GetType(),

       “ModalPopupTemplate.Resources.ModalPopupTemplateStyle_YUI.css”);

       break;

      

case PopupStyle.Clean:

       includeLocation =

       Page.ClientScript.GetWebResourceUrl(this.GetType(),

       “ModalPopupTemplate.Resources.ModalPopupTemplateStyle_Clean.css”);

       break;

      

default:

       break;

}

HtmlLink cssLink = new HtmlLink();

cssLink.Href = includeLocation;

cssLink.Attributes.Add(“rel”, “stylesheet”);

cssLink.Attributes.Add(“type”, “text/css”);

this.Page.Header.Controls.Add(cssLink);

}

This code retrieves the embedded resource URL from the library and adds a link to it in the page’s header.

Generating the ModalPopupExtender

The GenerateExtender method accepts one parameter: the control you wish to add the popup extender into.  You could remove the parameter and simply add it to the composite control’s ControlCollection, but I wanted to keep it open for later development.

private void GenerateExtender(Control container)

{

// Todo: Fix these hardcoded ID values for PopupControlId.

ModalPopupExtender mpe = new ModalPopupExtender();

mpe.BehaviorID = popupBehaviorId;

mpe.BackgroundCssClass = ModalBackgroundStyle;

mpe.PopupControlID = “popupPanel”;

mpe.TargetControlID = TargetControlId;

container.Controls.Add(mpe);

}

The code sets every property that you’d normally set on a ModalPopupExtender.  The only matter of disconnect at the moment is the PopupControlID’s value—I don’t like that hardcoded between this and the GeneratePanel method, but it’s minor for the time being.

Generating the Popup Panel

The popup panel’s code is cut down a bit for the post as it’s repetative: generate a Panel control, several labels for the header and body text, a few buttons and a link button, and then put it all together.

The most important part is to ensure that the DIV containers enclose the proper controls and that every tag closes itself, etc.

First off, we see the popupPanel setting it’s ID (to match the ID set in the ModalPopupExtender), CSS Class, and an additional style attribute to hide it (to prevent the blip of it appearing on page load).

The rest of the HTML and controls are interwoven between LiteralControls for exact HTML output.

popupPanel.ID = “popupPanel”;

popupPanel.CssClass = PanelStyle;

popupPanel.Style.Add(HtmlTextWriterStyle.Display, “none”);

 

popupPanel.Controls.Add(

new LiteralControl(“<div class=’” +

ContainerStyle + “‘>\n\t<div class=’” +

HeaderStyle + “‘>\n\t\t”));

popupPanel.Controls.Add(headerText);

popupPanel.Controls.Add(closeButton);

popupPanel.Controls.Add(

new LiteralControl(“\n\t</div>”));

 

popupPanel.Controls.Add(

new LiteralControl(“\n\t<div class=’” +

BodyStyle + “‘>\n\t\t”));

popupPanel.Controls.Add(bodyText);

popupPanel.Controls.Add(

new LiteralControl(“\n\t</div>”));

 

popupPanel.Controls.Add(

new LiteralControl(“\n\t<div class=’” +

FooterStyle + “‘>”));

popupPanel.Controls.Add(okButton);

popupPanel.Controls.Add(cancelButton);

popupPanel.Controls.Add(

new LiteralControl(“\n\t</div>\n</div>”));

Finally, this method, GeneratePanel, also accepts a control parameter to add the control to a specified collection.

Putting it together — CreateChildControls

The Composite Control’s method — CreateChildControls — is where the magic happens. 

protected override void CreateChildControls()

{

base.Controls.Clear();

 

if (!this.ChildControlsCreated)

       {

              GenerateExtender(this);

GeneratePanel(this);

}

 

base.CreateChildControls();

}

It’s usually a good practice to clear the composite control’s ControlCollection before starting—just to be sure that you know exactly what’s being rendered.  From there, call our Extender and Panel generation methods and place them in Composite Control’s control collection (this).

That’s it, you’re ready to add it to the page.  For more information about how to add it to the page and the control’s parameters, as well as the full source code and a demonstration site, visit the Creating a Modal Popup Template Control posting from 5 November 2007.

Creating a Modal Popup Template Control

November 5, 2007 8 comments

Download : .NET 3.5 Source Project

The ModalPopupExtender is one of my favorite AJAX extenders.  It provides a slick UI experience for little overhead.  The most difficult part of implementing the extender is recreating the popup panels over and over again for similar tasks.

ModalPopupTemplate with Matt Berseth's YUI CSS

To rectify this and create a “template” for use in our organization, I created a custom composite control that encapsulates

  • Creation of the AJAXToolkit’s ModalPopupExtender,
  • Creation of a Panel control,
  • Styles the Panel according to pre-set styles or custom styles,
  • Ties the Panel and Extender together,
  • Passes various events to the common UI elements of the popup,
  • Allows the popup’s events to be visible to other controls on the page.

As it stands, this is a prototype and needs quite a bit more tweaking before I’d put it into production; however, it stands as a fun project to tinker with. This will be an ongoing project and as I finish or update various aspects of the control, I’ll post up the changes.  I’m also interested in feedback and ideas for improvement. :)

The Control’s Structure

The ModalPopupTemplate's class diagram.

Here you can see the properties that are configurable with the control as well as the public and private methods and events.  I’ve also included the PopupStyle enumeration which prestyles the popup.

  • _Element_Style (BodyStyle, ContainerStyle, etc) properties accept strings from your embeded or attached CSS.
  • DefaultStyle is linked to the PopupStyle enumeration (and may lend itself to rename eventually).  The example I showed above is the YUI theme which uses Matt Berseth’s YUI Css.  I’ve also included a “Clean” theme similar to what we use in our projects at work.  I hope to grow the collection of themes as time progresses.
  • OnOkClick, OnCancelClick, and OnCloseClick methods link to the corresponding buttons on the popup and throw the like named events.  By default, if these events are not tied to methods in your project, they simply close the popup window.
  • BodyText and HeaderText are the two primary configuration elements of the popup.

Here’s an example including shaky arrow lines matching the properties to their relative location.  For examples of the Style (ContainerStyle, BodySTyle, HeaderStyle, etc) check out Matt Berseth’s YUI example—the CSS is the same (Thanks Matt for an EXCELLENT job and template to follow!)

Elements of the ModalPopupTemplate

Control Usage

Using the control on your .NET page is quite simple.  Remember, as with the normal ModalPopupExtender, your ModalPopupTemplate control must be in the same UpdatePanel as the TargetControl that activates it.  You’ll also need to ensure that EnablePartialRendering is set to true for your ScriptManager control.

<asp:UpdatePanel ID=”updatePanel” runat=”server” UpdateMode=”Conditional”>

<ContentTemplate>

<asp:Button ID=”btnTrigger” runat=”server” Text=”Show Popup” />

<cc1:ModalPopupTemplate

ID=”ModalPopupTemplate1″

runat=”server”

DefaultStyle=”YUI”

HeaderText=”Load Product Information”

BodyText=”Are you sure you want to load the product information?”

TargetControlId=”btnTrigger”

OnOkClick=”LoadDataTable” />

</ContentTemplate>

</asp:UpdatePanel>

How it Works

I’ll dig into how it works in the next posting—being somewhat late and being very sick and on some good drugs isn’t conducive to lots of writing. :)  If you can’t wait, download the source and go—it’s pretty well code commented.

kick it on DotNetKicks.com

Creating a Google AJAX Search Control in .NET

October 30, 2007 13 comments

As I discussed yesterday, the current non-SOAP Google approach is to use 100% JavaScript and their own custom UIs.  That really annoys me that I can’t take the service, call it, pass along some values, and get search results back.

My next thought was, if nothing else, encapsulate all the odd options and such into a nice little control.  This isn’t necessary for the Yahoo! search, as it’s SDK has it’s own controls, result objects, etc.  For the full list of Google AJAX Search options, check out the class reference.

Download .net 3.5 Complete Project [updated 30 Oct 07/10:55]

Our control has five properties:

  • The Google AJAX Search API Key: this string property is for the key specific to this particular instance and is URL aware, so you’ll need one per application (or directory).
  • Four “Enable” properties: EnableWebSearch, EnableImageSearch, EnableVideoSearch, EnableBlogSearch.  These are booleans are true by default and toggle the searchers applied to the control.  I made these toggleable because in some environments, like at my office, Google’s Image and Video searches are blocked, and others may not want those results. :)

The only method to override in our custom control is CreateChildControls; we’ll use it to populate the page with our JavaScripts.

protected override void CreateChildControls()

{

base.Page.ClientScript.RegisterClientScriptInclude(“apiScript”,

http://www.google.com/jsapi?key=&#8221; + this.Key);

StringBuilder searchers = new StringBuilder();

       searchers.AppendLine(“google.load(‘search’, ’1′);”);

       searchers.AppendLine(“function initialize() {“);

searchers.AppendLine(“\tvar searchControl = new

google.search.SearchControl();”);

       if (EnableWebSearch)

searchers.AppendLine(“\tsearchControl.addSearcher(new

google.search.WebSearch());”);

if (EnableImageSearch)

searchers.AppendLine(“\tsearchControl.addSearcher(new

google.search.ImageSearch());”);

if (EnableVideoSearch)

searchers.AppendLine(“\tsearchControl.addSearcher(new

google.search.VideoSearch());”);

if (EnableBlogSearch)

searchers.AppendLine(“\tsearchControl.addSearcher(new

google.search.BlogSearch());”);

searchers.AppendLine(“\tsearchControl.draw(document.getElementById(‘” +

this.ClientID + “‘));”);

searchers.AppendLine(“}”);

       searchers.AppendLine(“google.setOnLoadCallback(initialize);”);

 

       base.Page.ClientScript.RegisterClientScriptBlock(this.GetType(),

“searchers”,

             searchers.ToString(), true);

}

The apiScript provides the link to the Google JavaScript objects (and passed along the unique key).  The searchers is the guts of the search component and generates a JavaScript block wherever you place your control. 

Notice on the .draw method of the searchControl, it’s drawing back to itself (the control, by default, generates a span tag; we’re simply returning the “drawing” of the control back to that.  It’s possible to add another property, something like TargetControlId, and use that to separate out the search logic and the actual location the search UI is presented.

To place the control on your page, drop and drag it from the toolbar, or code.  Here’s an example with the VideoSearch disabled.

<googleControls:GoogleSearch

ID=”GoogleSearch1″

runat=”server”

EnableVideoSearch=”false”

Key=”KEYHERE” />

Unfortunately, this still doesn’t resolve using the Search API for non-web interfaces. :(

Follow

Get every new post delivered to your Inbox.