Thursday, September 21, 2006
This has been floating around for a little while and I can't say how many times I've watched it.  I am a life-long fan of "Weird Al" Yankovic and get a kick out of his songs, this one in particular.  I could go on and on about my favorite songs, etc, etc, but that would border on maniacal, but I don't want to reveal, er, insinuate that.  Maybe this one hits home because I relate in so many ways.
Thursday, September 21, 2006 6:44:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

I tend to shy away from Grid-based controls, generally favoring the Repeater-style controls when performing ASP.NET databinding; usually because I get more flexibility in the layout of the Repeater-style controls, not because I don't like grids.  Grids, like most everything have their place.

I was doing some databinding on an small ASP.NET application wherein I was using a GridView control and needed to format a date column.  I was setting the DataFormatString property to the format I desired (i.e. {0:MM/dd/yyyy}), but was dismayed that the date format wasn't taking effect.

The problem is easily resolved by setting the HtmlEncode property of the BoundField to false, thereby not encoding the column to HTML text before being formatted.

<asp:boundfield datafield="DeliveryDate" dataformatstring="{0:MM/dd/yyyy}" htmlencode="false" headertext="Delivery Date" />

Simple.

Thursday, September 21, 2006 2:02:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [8]  |  Trackback
 Friday, September 15, 2006

There is a very cool feature built into .NET (has been since the beginning) that I find not too many people know about called an Extender.  Well, an Extender isn't so much of a feature as it is an implementation of an interface formally called IExtenderProvider, but for brevity, I'll simply call implementors of the IExtenderProvider "Extenders".

An Extender class is one that provides additional functionality to a control or controls by augmenting its property set and providing the corresponding behavior.  An example of an Extender with which many people are familiar is the ToolTip.  Have you ever noticed that controls don't have a ToolTip property?  This is easily remedied by dragging a ToolTip control onto your form.  The ToolTip takes residence in the tray at the bottom of the designer.  All of the sudden all of the controls on the form magically have a new 'ToolTip' property.  In fact, the property is displayed more like "ToolTip on ToolTip1" to indicate the name of the control providing the property to the control.  This is the Extender in action.  The ToolTip control essentially provides one or more properties to a given type or types of controls.

Creating Extenders is remarkably easy to do, but there are some nuances to it that I'd like to explore here for a bit.  Basically the steps are as follows:

  1. Simply create a class (either a UserControl or a Component depending on whether or not you want your Extender to have a visual presence on the form) that implements the IExtenderProvider interface.
  2. Decorate the class with the [ProvidePropertyAttribute] specifying the name of the property and the type|type name of the control|component to be extended.
  3. Implement the IExtenderProvider interface (which consists of a single method called CanExtend).
  4. Because our Extender provides the property to the control, the control itself has no notion (or even knowledge) of this property.  Therefore, the onus is on the Extender to be able to store the associated property values for each control extended on the form.  I like to represent this storage with a Hashtable keyed off of the control being extended.  Create the property Hashtable.
  5. This now, is the key to making it work:  you must create two public methods whose name matches the property name specified in the [ProvidePropertyAttribute] from step 2, prefixed with 'Get' and 'Set' respectively.  The designer looks for these methods and calls them to persist property settings.  While these are technically 'methods', they behave as a property would (I wish we could simply create a property definition, but alas).
  6. For additional design-time support and control, feel free to decorate the 'Get' method with attributes of your choice (such as [CategoryAttribute] or [DescriptionAttribute]).

A common demo use case for an Extender is to provide visual feedback to the user based on some event or occurrence in the form.  Examples might include an Extender that provides a "ContextDescription" property such that on mouse over on a control, the description is displayed elsewhere on the form (or on the Extender itself).  Perhaps you want to highlight the control over which the mouse is positioned to give nice visual feedback to the user, to enhance accessibility of your applications, or for training purposes.  The list goes on and on.

One very cool aspect of Extenders is that in many ways, the Extender provides functionality that would otherwise be difficult or tedious to obtain.  For instance, if you want to implement the "ContextDescription" example above, you could do one of the following:

  • Write all of the event code on the containing form and hardcode all of the descriptions.  This is 1) tedious and 2) prone to errors and changes.  What if you reparent your controls to a new/different container? does your event code need to change?  It might.  If you move them to another form you'll have to reimplement the functionality there.  It becomes a burden to maintain.
  • Subclass (inherit) the control to provide the desired functionality or to raise the appropriate events.  This is more complicated and not as universally applicable.  For instance, what if you wanted the functionality to work for both Labels and TextBoxes?  What if you wanted to add Buttons to the mix?  Subclassing each of these is a pain and not very extensible.

I've created a very simple yet fun Extender that provides feedback as the user moves the mouse over a DataGridView control, highlighting the cell that the user is over with a color of their choice.   This simple example illustrates the techniques mentioned above:

using System;
using System.Collections;
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;

namespace DataGridViewExtenderExample.Components {

   [ProvideProperty("CellHighlightColor", typeof(DataGridView))]
   public partial class DataGridViewCellHighlighterExtender : Component, IExtenderProvider {
      public DataGridViewCellHighlighterExtender() {
         InitializeComponent();
      }

      public DataGridViewCellHighlighterExtender(IContainer container) {
         container.Add(this);
         InitializeComponent();
      }

      private const int InvalidCell = -1;

      private Hashtable        _properties = new Hashtable();
      private DataGridViewCell _lastCell;
      private int              _lastCol = InvalidCell,
                               _lastRow = InvalidCell;

      [Category("Appearance")]
      [Description("Sets or returns the color to highlight the cell as the mouse moves over the cell.")]
      public Color GetCellHighlightColor(Control control) {
         object color = _properties[control];
         return ( null == color ? SystemColors.Window : (Color)color );
      }

      public void SetCellHighlightColor(Control control, Color value) {
         DataGridView grid = control as DataGridView;
         MouseEventHandler ehMove = new MouseEventHandler(mouseMove);
         EventHandler ehLeave = new EventHandler(mouseLeave);

         if ( SystemColors.Window == value ) {
            _properties.Remove(grid);
            grid.MouseMove -= ehMove;
            grid.MouseLeave -= ehLeave;
         }
         else {
            _properties[grid] = value;
            grid.MouseMove += ehMove;
            grid.MouseLeave += ehLeave;
         }
      }

      bool IExtenderProvider.CanExtend(object extendee) {
         return ( extendee is DataGridView );
      }

      private void mouseMove(object sender, MouseEventArgs e) {
         DataGridView grid = sender as DataGridView;
         DataGridView.HitTestInfo hti = grid.HitTest(e.X, e.Y);
         int col = hti.ColumnIndex;
         int row = hti.RowIndex;

         if ( col != _lastCol || row != _lastRow )
            restoreCell();

         if ( col >= 0 && row >= 0 ) {
            DataGridViewCell cell = grid[col, row];
            cell.Style.BackColor = GetCellHighlightColor(grid);

            _lastCell = cell;
            _lastCol = col;
            _lastRow = row;
         }
      }

      private void mouseLeave(object sender, EventArgs e) {
         restoreCell();
      }

      private void restoreCell() {
         if ( null != _lastCell ) {
            _lastCell.Style.BackColor = SystemColors.Window;
            _lastCell = null;
         }
      }
   }

}

Enjoy!  As you can see, there's not much to it.  You can download an entire sample application that puts the Extender to work.  :)

Friday, September 15, 2006 3:12:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [2]  |  Trackback
 Thursday, September 14, 2006

I had a lot of fun tonight at the Utah .NET User Group - I always do.  We had a very interactive, exciting discussion on Regular Expressions in .NET.  Despite the inclement weather this evening we had a pretty decent turnout.  Robert Merrill represented SOS Technical which was the sponsor tonight - thanks again!

The majority of the discussion today focused on how to "think" in regular expressions, and how to approach them by applying the principles of character classes, metacharacters, alternations, groupings, etc.  I had put together a very simple application (which I'll post here on the blog in the morning when I clean it up a bit) for testing regular expressions and viewing their results which was a fantastic aid in presenting the concepts.  I had a great time and I presume that everyone else in attendance did as well. :)

Thursday, September 14, 2006 6:21:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Wednesday, September 13, 2006

For all those out there interested in attending the Utah .NET User Group, we're meeting tomorrow (September 14th, 2006) at Neumont University in South Jordan.  This month the privilege is mine to present on the topic of Regular Expressions.  I'm very excited about the topic and am looking forward to it.  This can be a challenging topic to discuss, but I hope there's a lot of participation.

Anyone have any suggestions or things about Regular Expressions that they would like me to cover?

Time: 6:00 PM
Date: Thursday, September 14th, 2006
Place: Neumont University (10701 South River Front Parkway, South Jordan, Utah)

Wednesday, September 13, 2006 1:16:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  |  Trackback

I have taken the time to finally install and get Live Writer installed and running - if nothing else to test it out.  I'm kinda liking it.  I can already tell that there are some things that I'd like for it to do a little differently, but I'm happy to experiment with it.

It sure beats having to deal with the FreeTextBox that is included with the .Text blog engine.  Nothing against FreeTextBox, per se, but there were always a few things that really bugged me with it (mostly how I couldn't ever go back and edit XML/HTML/Markup in my blog posts without resorting to my own 'fly by night' app that I threw together just so allow me to edit them).

In fact, I had installed Live Writer several weeks ago but was not successful in getting it set up to work with .Text, nor did I really take the time to do so.  However, I was reading Miguel Jimenez's blog today and found a nice little nugget.

When setting up a .Text blog in Live Writer you specify the proper blog url and your user name and password.  On the second screen you specify to use a Custom Blog (MetaBlogAPI) with a url of http://yoursite/blogname/services/metablogapi.aspx.  At first this didn't work for me.  If you get an error indicating that the user name is invalid, make sure that Web Services are enabled for your blog.  I had disabled them long ago, but had to reenable them today for this to work.

I'm digging this.  It's nice and convenient and I don't have to have a live connection to make my posts.  There are a million tools out there like this one, but this suits my needs just fine.

Wednesday, September 13, 2006 10:50:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, September 11, 2006

I usually refrain from making political or patriotic posts on this blog, but in lieu of the date, I'd like to make an exception.

There are events in one's life that leave an indelible mark in one's memory, an impression forever engraven.  I've been contemplating this a bit lately with today marking the 5 year (5 years!) mark of the Sept 11th terrorist attacks in New York City.  I can, as I'm sure many of you also can also, remember where you were at the moment you found out.  I was in Redmond, working for Microsoft at the time, and was there for training.  I recall vividly seeing the news on MSNBC across the campus and the hotel.  My first thoughts were of my family (I promptly called home to tell of the incident) and the well being of my loved ones.  I also wondered if I'd be able to fly home later that week.  I felt deeply hurt by the attack, and while I don't personally know anyone who lives on the east coast my heart was with them.

In similar fashion, I distinctly remember when the Challenger Space Shuttle exploded.  I recall sitting with my classmates in grade school watching the launch on the TV at the front of the room.  Just a few years prior we had the privilege of having the Space Shuttle Columbia land at White Sands, just a short 45 drive from my house in New Mexico.  I had great dreams and aspiration of becoming an astronaut all through my childhood, even into my teen years.  When we saw the explosion and ensuring plumes of smoke, my heart sank.  I won't say that this discouraged me in any way from becoming an astronaut (because it didn't), but it left such a feeling of mourning and sadness in my soul for the astronauts and their families.  Particularly, I felt moved for Christa McAuliffe and her family.

I distinctly remember the assassination attempt on Reagan's life.  While I was only a child at the time I recall feeling anxiety for him to recover.  I remember watching it on the news at my grandparents' house in Las Cruces.  We were all gathered around the TV amazed at the horrible experience.  I did and to this day, deeply admire and respect President Reagan, for who he is and what he stood up for.

These are just a few of the many, many events, albeit tragic events, that have left deep impressions on my mind (there are many other moments of elation and happiness that are just as poignant).

Despite these and other events, as a people we continuously unite under pressure and stand up for what we believe in.  May we be constantly united and stand up for what's right, not just in times of turmoil, but at all times and in all places.

Monday, September 11, 2006 5:38:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, September 07, 2006

By way of announcement, I thought I'd pass this along.  I'm very excited about it and plan on participating.

Utah Code Camp
October 21st 2006
Neumont University
Salt Lake City, UT
The local .NET Users Group and SQL Server Users Group is conducting a "Code Camp" for local software programmers next month at Neumont University.  The code camp follows the Code camp manifesto that it is for the community by the community and always free.  We are looking forward to excellent sessions on lots of different topics. 
 
The Saturday, October 21st event is scheduled from 8:00 AM to 5:00 PM.
The conference is free please register at
www.msutahevents.com.  We will have sessions for both Developers and DBA's. 
We will have a Sponsors area with lots of giveaways! 
If you would like to speak or are interested in speaking Please email Pat Wright at
pat_wright@sqlpass.org.  Or visit www.msutahevents.com  for more
information.

Thursday, September 07, 2006 5:59:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Over the past several months (years) I've given a series of presentations on the topic of Threading in .NET.  These presentations have been to various .NET User Groups, at company 'brown-bag events', or even over Live Meeting.  They have been a real treat for me as I love the topic and it's near and dear to my heart.  I came across this free e-Book (also available as a PDF) that I would highly recommend to anyone wanting to dig in and learn more about Threading in .NET.  The e-Book is written using the C# language, but that shouldn't be a hindrance to anyone wanting to understand the inner workings of the topic.

Enjoy!

Thursday, September 07, 2006 9:56:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Wednesday, September 06, 2006

All in all, I must say that I am indeed a fan of the Web Application Projects (WAP) in VS 2005.  If you're familiar with web development in the VS 2003/.NET 1.1 world, then this provides a much more comfortable and familiar experience than the Web Site Projects (WSP) in VS 2005 out of the box.  I won't belabor the benefits of using them here as they have been covered extensively online.

I had created a WAP several months ago and came back to recently to update it and work on enhancing the functionality.  By way of tendencies, I like to design such that each class is an internal class (that is, not publically exposed) with internal constructors, methods, properties, etc.  As such, when I make a class public my intentions are clearer and the scope of the class is well defined.  Well, such a model doesn't work too well with WSP due to the myriad of assemblies created.  Today, however, in testing my application I was presented with an error message indicating that a class was “inaccessible due to its protection level”.  This warning indicates to me that I'm trying to use a class out of its defined scope (in this case - internal).

As it turns out my .aspx code-behind IS in the same project as the internal class, but the WAP was exhibiting behaviors reminiscent of the WSP.  In fact, the project would compile and I'd get .dlls generated in my \bin folder, but at runtime the .aspx pages were getting compiled into their own dlls.

The easy way to fix this (and I didn't know this wasn't here before) is to do the following:

  1. Right-click on the WAP in the solution explorer
  2. Select “Convert to Web Application”

That fixed up whatever was wrong with the project and now it works like a charm.

Wednesday, September 06, 2006 2:33:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback