Tuesday, September 26, 2006

This has been a tad frustrating but ever since upgrading my computer to a Dell Precision M90 (Dual Core) from a Dell Inspiron 8600 my favorite virtual drive application (DAEMON Tools) has not worked.  This has been a known issue with version 4.03 and well documented in the forums on their website, but on a whim today I decided to check to see if there were any updates.  As it so happens 4.06 was released just today.

I downloaded it and installed it and I'm happy to say the dual-core issue has been fixed - it worked first try!  :)  I'm so happy.

[UPDATE: 09/26/2006]
As it turns out, because I run as a non-administrator there is a bit of an issue running DAEMON Tools 4.06 once I rebooted.  To remedy this, I had to alter the registry to run DAEMON Tools as an administrator rather than my account at startup.  As a side effect, I have to provide admin credentials at boot up, but I'm willing to do this in order to get the software to work.

1. Open the Registry Editor (regedit.exe or regedt32.exe)
2. Open to HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Run
3. Edit the string value called DAEMON Tools to have a value that resembles:

runas /user:MACHINENAME\Administrator "\"C:\\Program Files\\DAEMON Tools\\daemon.exe\" -lang 1033"

Tuesday, September 26, 2006 5:31:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Sunday, September 24, 2006

In doing a little ASP.NET 2.0 databinding to a DropDownList control I was presented with a nice little error:

"'[ddlcontrolname]' has a SelectedValue with is invalid because it does not exist in the list of items. Parameter name: value"

Well, this is occurring on a postback for one DropDownList on a requery of a dependent DropDownList.  In other words, DDL01 performs an autopostback which forces DDL02 to requery its list.  The error is occurring because the SelectedValue that was originally bound to DDL02 is no longer in the set of data now associated with it.

You might try, as I did, to work around this by setting the SelectedValue property to null or string.Empty prior to rebinding, but that didn't seem to work for me.

There is a very easy solution to this dilemma, however.  In my case, all I had to do was clear the list, then set SelectedValue to null, then rebind as the following method does:

private void bindToList(DropDownList ddl, DataSet ds, string textFieldName, string valueFieldName) {
   // clear out any previous selection to avoid the ugly IndexOutOfRangeException
   ddl.Items.Clear();
   ddl.SelectedValue = null;

   // perform databinding as normal
   ddl.DataSource = ds;
   ddl.DataTextField = textFieldName;
   ddl.DataValueField = valueFieldName;
   ddl.DataBind();
}

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

I just read this post today and must say that while I don't necessarily share Steve's guilt, I most certainly get pleasure out of taking the occasional nap - especially during the day.  Of late (read as 'over the past 6 or so years') I have not had taken the opportunity to rest my weary eyes as I would have liked to, though I've stolen a few winks here and there.

I very much enjoy when I can crash for about 15 minutes to an hour in the mid afternoon, in part for the wonderful refreshing feeling when I arise, but also because it allows me to get more done.  In truthfulness, when I have the chance I like to indulge.  I find that I'm way more productive and I can focus more on the work that I have to do.

Many years ago I worked in a technical support group at a company in Salt Lake City.  My responsibilities mostly revolved around helping customers with their software issues revolving around the job-costing/AP/AR/GL software that we provided to them and was developed in-house.  Great times.  One of the best memories that I have of that place is that I was able to take a nap over lunch...and everyone knew about it. :)  I'd eat my lunch (which was usually pretty small and consumed in about 10 minutes) and for the remaining 45-50 minutes of the lunch hour I'd retire to a remote room in the rear and rest.  Back in those days my body clock was quite attuned to the time and though I'd close my eyes and be officially 'out of it' for the duration, I would snap-to at exactly the hour and return to my desk completely refreshed and ready to tackle the remaining hours in the day.  Never once was I late, something of which I was quite proud.

I think I gained this measure of control in the preceding years while I was in Mexico on a two-year mission.  There would be the occasional day where my companion and I would return to our house/apartment/room after lunch (during their offical siesta hour) and prepare for the remainder of the day.  I could crash for 20 minutes in a 'power nap' and instantly get up and be fully charged for the rest of the day.

These experiences and more have led me to be an advocate for napping.  They sure get me charged up and moving.

Are you a napper? Are you a sleeper-inner?  What helps you maintain your level of intensity during the day?

Sunday, September 24, 2006 6:10:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Friday, September 22, 2006

I recently created a small WebSite project in Visual Studio 2005, in part, to simply reaquire a feel for it.  In generally, my programming style and thinking falls more in line with the Web Application Projects which are akin to creating web projects in Visual Studio 2003.  The scope of this project is very small so I figured that it would be good to experiment with the WebSite project on a small scale...it seems to fit nicely.

That said, however, I have an ASPNETDB.mdf database that maintains membership for the website with a few canned users.  One thing that I do like in VS2005 is the "ASP.NET Configuration" option which launches a Cassini website for the administration of users, roles, permissions, etc that are maintained in the ASPNETDB.mdf database.

Once the database is moved over to the server, however, you lose the ability to run this management website...or so it may seem at first.

In fact, you have all of the management tools as part of the .NET 2.0 installation, but you have to wire it up.  So, if you want the nice ASP.NET Web Site Administration Tool on your server simply follow these steps:

  1. Create a new virtual directory that references %WINDIR%\Microsoft.NET\Framework\v2.0.50727\ASP.NETWebAdminFiles.  I called it ASP.NETWebAdminFiles.
  2. Make sure that the appopriate version of ASP.NET is used.  In this case, it should be .NET 2.0.
  3. On the directory security tab, disable anonymous access.
  4. Set the default document to default.aspx.

Then, to properly manage your website, you need to specify a couple of query string parameters: applicationPhysicalPath and applicationUrl.

For instance:

http://localhost/ASP.NETWebAdminFiles/default.aspx?applicationPhysicalPath=C:\TestWebsite\&applicationUrl=/

For each website, I set up a simple shortcut that provides quick access to the administration console.

Friday, September 22, 2006 10:27:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [12]  |  Trackback

Ok, maybe it's just that it's 4:30 AM and I need to get to sleep, but this is something that has bugged me for sometime, and it's just coming to a head right now.

I just don't get how VS2005's Publish Web Site option is all that helpful, especially on a second time around.  Let me explain.

I really like how simple it is to 'push' a website up to a server.  Simply enable FrontPage Extensions on the web site in IIS and viola, you can publish from VS2005.  Slick.  If you're publishing for the first time, it's all smooth and it pushes the entire website (content, databases, etc) as prescribed in your project in VS.

I would argue, however, that that's usually not the last time the website is touched.  Tweaks need to be made, new logic introduced, alternative site navigations added, etc.  In short, there's maintenance.  When you go to publish a second time around it will warn you with a message indicating that "Existing files in the destination location will be deleted.  Continue?".  While appreciate the warning, I think it's completely out of line.  The warning is, in fact, telling you the truth.  When you publish, ALL files, folders, etc in your target folder will be purged.  I think this is a bad thing in several ways.

In an effort to combat this work around this egregious behavior by excluding files from your project in an attempt to not upload them; this will, in fact, work - the files will not get uploaded, but they will disappear from the server all the same.

But the one thing that's really irking me right now is how it handles databases.

Suppose you're creating a website that uses SQL Server Express and have the customary ASPNETDB.mdf in the App_Data folder to maintain membership, profiles, roles, personalization settings, etc.  There's not a convenient mechanism to publish your website from Visual Studio because doing so will effectively destroy the target database, replacing it with the one from your development environment.

So what's the deal?  Why does it a) not give the option to skip the uploading of databases b) have to delete every stinkin' file?

Friday, September 22, 2006 9:46:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 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