Manual and Undefined ASP.NET Events

ASP.NET provides some very handy magic to map the .NET event model to the web. Normally, we're perfectly happy to let it handle all the details for us. There are those cases, though, where we need to pop the hood and get our hands dirty. I'll outline how ASP.NET events work behind the scenes, then show the two different ways we can work with them outside of the normal event handling patterns.

How ASP.NET Events Work

When you create a control on a page with an event, ASP.NET adds a javascript event handler to the HTML element for that control. The javascript takes a form similar to this:

__doPostBack(control, arguments);

The “control” parameter is the client ID of the control invoking the event. The “arguments” parameter defines the event. It usually just contains the name of the event, e.g. “click” or “selectionChanged”, though sometimes it carries additional contextual data.

When __doPostBack() is called, it sets two hidden form fields: __EVENTTARGET is set to the “control” parameter and __EVENTARGS is set to the “arguments” parameter. It then POSTs the containing <form> (which is why all ASP.NET pages must have a single <form> with runat=”server” on them).

Once the ASP.NET page receives the POST from with the form data, it begins the normal page lifecycle. After it’s loaded, it inspects the __EVENTTARGET value to figure out which control to pass the __EVENTARGS to.

Any control capable of responding to postback events must implement the IPostBackEventHandler interface. The interface contains a method, LoadPostData(eventArgument), which the page will call, passing __EVENTARGS as the eventArgument. From there, the control parses the event argument and performs further processing, which usually consists of firing the associated .NET events.

Generating and Handling ASP.NET Events Without Using .NET Events

It’s possible for you to create and respond to ASP.NET events without using .NET events and handlers. You can generate the events from anywhere, but handling them in such a manner requires that you create a class derived from Control that implements IPostBackEventHandler:

public class MyControl : Control, IPostBackEventHandler
{
    public void RaisePostBackEvent(string eventArgument)
    {
    }
}

Since eventArgument is a string, you can pass whatever arbitrary value you wish. The typical format in ASP.NET is “eventName:extraData”, but there’s no requirement that you follow that format. You can then act on that value in any matter you wish, including firing your own .NET events.

Note that if your class inherits from WebControl (including UserControl), you won’t be able to handle events in this fashion, as WebControl implements IPostBackEventHandler.LoadPostData() as a private method.

To generate an event, you simply need to call __doPostBack() in javascript, passing in a control’s client ID and the appropriate event arguments. ASP.NET also provides a method to generate javascript postback and callback code on the server side: Page.ClientScript.GetPostBackEventReference() and Page.ClientScript.GetCallbackEventReference() respectively. Placing the return value from these methods in the onclick event of an HTML control will allow you to fire your own arbitrary ASP.NET events.

Detecting ASP.NET Outside of the Event Handler

Sometimes you may need to determine what event is being processed outside the event handler, such as in the PageLoad method. Since __doPostBack() creates an event simply by setting form fields, you can determe what control and event by inspecting Request.Form["__EVENTTARGET"] and Request.Form["__EVENTARGS"] respectively.

protected override void OnLoad(EventArgs e)
{
    base.OnLoad(e);

    if(IsPostBack
        && Request.Form["__EVENTTARGET"] == myControl.ClientID
        && Request.Form["__EVENTARGS"].StartsWith("click"))
    {
        // We know we’re going to end up processing the click event on myControl.
    }
}

Please note that this method of detecting events goes contrary to the ASP.NET event handling model and can lead to difficulties in understanding and debugging your code. It’s usually best to find a solution that works within the existing framework when handling events.

Custom Buttons with CSS Sprites

I published an article on my company’s blog about creating custom buttons using CSS sprites. You can view it here. I didn’t have the space to expand on indicating other button states with sprites, but be aware that you can apply the same technique used for the disabled styles to pseudo-classes like :active and :hover.

WPF MVC FTW!

The Model/View/Controller paradigm has been making big news in the ASP.NET development community as of late. Mac programmers and crusty old MFC devs may roll their eyes, but I think any attempt to draw developers’ attention to higher order design principles is laudable.

ASP.NET may have required some finagling to get it to work in the MVC pattern, but I’ve found that WPF is perfectly aligned for MVC design. Since you’re allowed to pass POCO’s (Plain Old C# Objects) to UI elements, it’s simple as pie to separate your model from your presentation. I don’t have to worry about instantiating and initializing the right control for a particular data type; I simply define a DataTemplate for the class, and it magically uses the UI in the template wherever it sees an instance of that class.

modelsOne of my recent personal projects is for managing Magic: The Gathering card collections. I created a data entry app to allow for quick entry of large collections of MTG cards. Each card comes from a set, so my models were pretty obvious. I created a library project, and added a Card and a Set class, as well as some support classes, to the Models namespace. As per the MVC pattern, these models are exclusively for storing data and data-related logic. They contain no UI functionality whatsoever.

Now that I had my data, it was time for the UI. I decided to display the list of sets in a combo box, but I had a couple special needs. First, the cards don’t say which set they come from; instead, they show the set’s symbol, a small graphic unique to each set. I needed to display the symbols in the combo box so that the user could choose the correct set, even if they didn’t know the name. Second each set has a standard three letter abbreviation. I wanted the user to be able to type the abbreviation into the combo box to quickly select the desired set, without requiring moving the hands from keyboard to mouse.

I set out by creating a Views folder in my Interface project. For lack of imagination, I named the views after their respective models, though there can be many views for the same model and I may find myself having to rename them later. Each view inherits from ViewBase (itself inheriting from UserControl), which defines a Model dependency property and events for the Model property changing.

The set view went through several iterations to get the right data displayed in a compact space. Initially it was displaying everything from the release date to the number of cards in the set, but eventually I ended up with a very reasonable set of controls:

<Grid Margin="2" VerticalAlignment="Center" DataContext="{ Binding }">
    <Grid.ColumnDefinitions>
        <ColumnDefinition MaxWidth="33" />
        <ColumnDefinition MaxWidth="8" />
        <ColumnDefinition Width="*" />
        <ColumnDefinition MaxWidth="25" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
        <RowDefinition />
    </Grid.RowDefinitions>
    <TextBlock x:Name="lblAbbreviation" Grid.Column="0" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center" Text="{ Binding Path=Abbreviation }" />
    <TextBlock Grid.Column="1" Grid.Row="0" HorizontalAlignment="Left" Text="-" />
    <TextBlock x:Name="lblName" Grid.Column="2" Grid.Row="0" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold" Text="{ Binding Path=Name }" />
    <Image x:Name="imgSymbol" Grid.Column="3" Grid.Row="0" Stretch="None" HorizontalAlignment="Right" Source="{ Binding Path=Symbol }" />
</Grid>

Now for the magic of XAML and DataTemplate. I added a DataTemplate element to the resources for my main window:

<Window.Resources>
    <DataTemplate DataType="{x:Type Models:Set}">
        <Views:Set Model="{ Binding }" />
    </DataTemplate>
</Window.Resources>

Now whenever my window sees a Models.Set object, it will substitute it with a Views.Set control, passing in the Models.Set as the Model property.

Next, I created my combo box with the formatting I needed:

<ComboBox   x:Name="cboSet"
            IsEditable="False"
            IsReadOnly="True"
            TextSearch.TextPath="Abbreviation"
            HorizontalContentAlignment="Stretch"
            SelectionChanged="cboSet_SelectionChanged" />

Pretty simple stuff. The IsEditable and IsReadonly properties allow the user to type in the box to search the existing values (as opposed to adding new ones). The TextSearch.TextPath tells the combo box what property of the items to compare the user’s typing to. Setting it to “Abbreviation” means when the user types, it will be compared against the three-letter set abbreviation. Remember, I’m going to assign my POCO Models.Set class as the combo box items, not the Views.Set. WPF will take care of displaying my Models.Set’s as Views.Set’s. That means any properties I’m talking about will be on the model, not the view (the way it should be!)

Finally, it’s time for the big test.

cboSet.ItemsSource = Sets;

Compile and run…

combobox

Bingo!

I applied this same process to the Card view, as well as an internal class call HistoryItem. In the end, I got an app that looks like this:

MTG Collection Tracker

Proportional Image Resizing With XSLT

Technorati Tags: ,,

Let's say you have a bunch of different sized images that you want to constrain to some maximum dimension. You don't want to enlarge images smaller than you constraining dimension. If your limit was 150px, you might try the following:

<img>
    <xsl:attribute name="src">
        <xsl:value-of select="media/thumbnail/url" />
    </xsl:attribute>
 
    <xsl:if test="media/thumbnail/width > 150 or media/thumbnail/height > 150 ">
        <xsl:attribute name="style">
            width: 150px; height: 150px;
        </xsl:attribute>
    </xsl:if>
</img>

The problem with manually specifying the width and height in the style is that if the original image is not square (and most aren’t) the image will be distorted in one dimension. In order to prevent this distortion, you will need to size both dimensions by the same coefficient.

<img>
    <xsl:attribute name="src">
        <xsl:value-of select="media/thumbnail/url" />
    </xsl:attribute>
 
    <xsl:choose>
        <xsl:when test="media/thumbnail/width > 150 and media/thumbnail/width &gt;= media/thumbnail/height">
            <xsl:attribute name="width">
                <xsl:value-of select="(150 div media/thumbnail/width) * media/thumbnail/width" />px
            </xsl:attribute>
            <xsl:attribute name="height">
                <xsl:value-of select="(150 div media/thumbnail/width) * media/thumbnail/height" />px
            </xsl:attribute>
        </xsl:when>
 
        <xsl:when test="media/thumbnail/height > 150 and media/thumbnail/width &lt; media/thumbnail/height">
            <xsl:attribute name="width">
                <xsl:value-of select="(150 div media/thumbnail/height) * media/thumbnail/width" />
            </xsl:attribute>
            <xsl:attribute name="height">
                <xsl:value-of select="(150 div media/thumbnail/height) * media/thumbnail/height" />
            </xsl:attribute>
        </xsl:when>
    </xsl:choose>
</img>

In this version, we use an xsl:choose to determine if the height or width is the larger dimension. If the larger dimension is greater than our maximum (again, 150px in this example), then we calculate the percentage that 150px is of that dimension; this is our coefficient. We then multiply both dimension by the coefficient to get the final size: the largest dimension will be 150px, and the smallest will be size proportionally to 150px or less.

For those so inclined, here’s the sorta math:

let m be the desired maximum dimension

let w and h be the width and height of the image respectively

L = maximum(w, h)

k = m / L

w = w * k

h = h * k

Note that in the example above, we could have simplified it by just applying the percentages directly to the image dimensions instead of taking the extra step of multiplying it by the original dimension. I just liked being able to see that it was exactly 150px in the output.

Grouping with XSLT

I've been working on integrating FriendFeed into this site. For those who are unfamiliar with FriendFeed, it aggregates your activities across the social web and gathers them into a single feed, to which your friends can subscribe. It's a nifty utility with a wide range of supported services, from Twitter to Flickr to Disqus to Digg.

FriendFeed provides a full REST API that can provide results in JSON, XML, RSS, and Atom. Since my implementation doesn't require any client-side interactivity, I decided to use XML, transform it with XSLT on the server, and display the result in the page. The provided XML consists of a <feed> full of <entry>'s. Each entry has details such as the posted date, service (Flicker, Twitter, etc), and title.

One of my presentation requirements is that the items be grouped by date. I wanted to shw and "post" for each day, with each of the days entries beneath it. I found a good method that provides exactly what I need.

The crux of the functionality is using XSLT keys. Keys are essentially like database indexes, allowing you to quickly select without repeatedly traversing all of the nodes. You define a key as follows:

<xsl:key name="name-of-key" match="nodes-to-apply" use="value-to-index" /> 

The name is simply the string you want to use to refer to this key later. The match is the node you want to apply this key to. The use can be any child element, attribute, or computed value (using a function) defining what you want to be indexed.

In my case, I wanted to use the <updated> element, which containes the time and date the item was last updated. Since I was going to be grouping on the date and not the time, I used the Microsoft-specific time formatting function to truncate the time and format the date as a number:

<xsl:key name="entries-by-date" match="/feed/entry" use="ms:format-date(updated, 'yyyyMMdd')" /> 

Now I've defined a key called "entries-by-date" that will quickly pull up all matching <entry> elements for a given date in the format "20080614". The next step is to iterate through all of the dates and show the corresponding entries. Unfortunately, we can't just iterate through the key we created. Instead, we have to sort the <entry> elements by their formatted <updated> element (which we created the key for), then grab all of the other <entry>'s with the same key. We want to be sure to grab each <entry> only once. Here's a larger snippet showing how to acomplish this:

<!-- Root -->
<xsl:template match="/feed">
 
    <!-- Group by date -->
    <xsl:for-each select="entry[count(. | key('entries-by-date', ms:format-date(updated, 'yyyyMMdd'))[1]) = 1]">
 
        <!-- Sort by date -->
        <xsl:sort select="updated" data-type="number" order="descending" />
    
        <!-- Show date groups -->
        <xsl:call-template name="dateGrouping" />
 
    </xsl:for-each>
 
</xsl:template>

The magic happens in the for-each. First, we take the current node and the first node from the key (aka index) with the same calculated date value. We create a set with these two nodes using the "|" operator. If the nodes are different, we'll get a set containing two nodes. If they are the same, there will only be one node in the set. We then check the number of nodes in the set using the count() function. If the count is one, we use it in the for-each; otherwise, we skip it. In the end, this gives us the first entry each date.

After we have our target date to group by, we want to display each <entry> with the same date. In my stylesheet, I implemented it in the "dateGrouping" template. The actual code is pretty easy:

<xsl:template name="dateGrouping">
    <!-- You could output the date header here -->
    <xsl:for-each select="key('entries-by-date', ms:format-date(updated, 'yyyyMMdd'))">
        <xsl:apply-templates select="." />
    </xsl:for-each>
</xsl:template>

We use the key() function to get every node in the given key with the matching value. We then apply the formatting to each node to get our final result.

Poker-Bot Competition

People enjoy the idea of creating things to battle with each other, ala BattleBots. Here’s an idea that is both fun and potentially lucrative: a bot-only online poker server for real money. You would put money into an account an upload your own custom-written poker bot. Your bot would play until it ran out of money. It would keep its earnings, and you would be allowed to withdraw them.

The idea is that you would lets these bots run for a long time and play many games (if only machines are playing, games would go incredibly fast). To that end, you would need a bot to be able to choose what buy-in it wanted to play at, so it could adjust up or down depending on its success rate.

It would be of critical importance to not allow the bots to communicate or know who they’re playing against. If they could coordinate, then could game the system to always win. To that end, each bot would be assigned to a random table, and no identifying information about either the tables (so two bots could know if they’re at the same table) or the other players would be given.

Since it’s just machines playing, the human factor would be removed. At first glance, that would make it seem like a purely mathematical exercise. However, some strategies would become apparent, and a bot can be coded to detect and play against them. Additionally, a bot could employ random factors to protect against these types of detections. It would make the game very dynamic.

del.icio.us Tags: ,

building a blog

bricks

My first inclination when planning this site was to roll my own blogging suite; I even convinced the admin to upgrade the server to .NET 3.5 so I could use LINQ. My previous experiences with content management systems left me turned off to the idea of pre-defined layouts and constricting plug-in API’s. I wanted to be able to include every feature to take my fancy at the drop of a hat (and the upload of a .cs file). I wanted to use every AJAX/XHTML/CSS trick in the book as well as new ones that come along. If there’s one thing I knew, it’s that I would much too quickly find the bounds of the likes of Mambo, Drupal, and Joomla.

Unfortunately, I can’t design the paint job for a barn. I have the knowledge and tools for great functionality. Great looks? Not so much.

My next thought was to take an existing open source blogging package and adapt the theming engine and any attractive themes. Luckily for me, the first Google result for “.net open source blog engine” was BlogEngine.NET. A quick peek through the project showed that there has been a lot of progress since my forays in to open source CMS. I was sold. I dropped any ideas of creating my own software and installed the entire package.

So far, I couldn’t be happier. Instead of imposing an architecture on you, you are presented with what could be considered a reference application, and you’re free to go to town with whatever ASP.NET techniques you want. Theming ASP.NET master pages. You can use your own server and user controls without any restrictions. And since it’s open source, you can add whatever core functionality you want. In short, it’s what I like to imaging I would have written.

Back to the core issue of design, BlogEngine.NET comes with a few basic themes, and there is a nice, if a bit anemic, theme gallery on their site (though it was broken when I tried to use it). It turns out, however, that there is a thriving community of free XHTML/CSS site designs. There is a huge selection available at (and significant overlap between) oswd.org and opendesignes.org. They’re realeased under the Creative Commons Attribution License 2.5, so you’re free to do whatever you want with them (including commercial uses), as long as you give credit to the original authors.

I also found an interesting site called Disqus, which allows you to implement threaded comments without any local resources. Additionally, it allows users to track comments and reputation across multiple sites. There is a similar service called Intense Debate, though I went with Disqus since it’s integrated with FriendFeed.

There are, of course, many other useful services, such as FeedBurner for stats on your RSS, Google Analytics for stats on your site, and Fli

del.icio.us Tags: ,

ckr for images. I plan to add more to the site as I come across them.

A Home for My Words

Welcome to "Nothing Is a Lot of Something dot com", a non-sensical name leading to an eminently sensical destination, assuming your sense is to read about practical software development interspersed with musings on life from the perspective of one, Jason Addington.

If that doesn't make sense to you, then I'm sorry. To make up for it, I'll give you this link -- link! -- to take you back to whatever more interesting place you came from. Have fun. You probably won't be missed.

Now that all of the boring people are gone, let's get down to business! I've created this blog for three main reasons:

  1. To share things I learn regarding software development in order to spread understanding and understand better myself.
  2. To write down my thoughts so I can hear what others think about them.
  3. To do something with this domain name that I bought simply because I thought it was funny.

Sadly, the third reason was the most motivating factor. Still, like oak trees from acorns, great things can come from small ideas! So, on this surreptitiously auspicious day, I give you the smallest of ideas planted in the most fertile of grounds, in the hope that one day we may all enjoy the, uh, shade of our efforts and the, er, acorn flour of our collective cognation?

Meh, I just hope I can remember to water it.