Tuesday, December 28, 2004
I am very excited to just find that NDoc 1.3 was released on Dec 17, 2004.  For the uninitiated, NDoc is a fantastic tool used to take XML comments and convert them to documentation.  Get your copy now!.
Tuesday, December 28, 2004 4:09:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

I recently encountered an interesting situation.  I am subclassing the RichTextBox control to support some syntax highlighting and custom selection mechanism unique to an application that I'm writing.  The control has two modes: simple and expert.  In the simple mode there are certain blocks of code that are identified by a string such as [KEYWORD].  When the user clicks in or navigates via the arrow keys into the keyword, the full keyword gets selected.  However, in expert mode, the [KEYWORD] expands to something much more verbose.

Additionally, this application has a toolbar from which the user can drag and drop keywords onto the RichTextBox (which I've dubbed RichEditor).  However, being an MDI application, the user might very well have multiple RichEditors each in a different mode.  I need a mechanism to drag a tool from the toolbox onto the RichEditor and then make a decision as to which text to display - the [KEYWORD] version, or the expanded text.

Easy I hear you say...and in fact I would tend to agree.  All you have to do is create a [Serializable()] class and pass it to the DoDragDrop() method of my toolbox item as in the following:

[Serializable()]
internal sealed class KeywordItem {
   private string _fullText;
   private string _keywordText;

   // properties and ctor that establish and expose the
   // two private text properties
   // ...
}

then within the toolbox item I might have the following:

DragDropEffects effects = this.DoDragDrop(new KeywordItem(...), DragDropEffects.Copy);

This is all fine and good.  Now it's time for me to implement the code in the RichEditor to support the dragging and dropping of the appropriate text:

protected override void OnDragEnter(DragEventArgs e) {
   base.OnDragEnter(e);
   e.Effect = !e.Data.GetDataPresent(typeof(KeywordItem)) ? DragDropEffects.None : DragDropEffects.Copy;
}

protected override void OnDragDrop(DragEventArgs e) {
   base.OnDragDrop(e);
   KeywordItem kw = (KeywordItem)e.Data.GetData(typeof(KeywordItem));
   if ( null != kw ) {
      int selStart = this.SelectionStart;
      switch ( _mode ) {
         case Mode.Basic:
            this.SelectedText = kw.KeywordText;
            this.Select(selStart, kw.KeywordText.Length);
            break;

         case Mode.Advanced:
            this.SelectedText = kw.FullText;
            this.Select(selStart, kw.FullText.Length);
            break;
      }

   }
}

This gets the job done, and for the most part I might consider this functional and move on, however an astute observer of the behavior might be troubled.  To begin with, usually a TextBox provides feedback of the drag/drop locationi by moving the insertion point and following the mouse.  This code does not enable that functionality.

The reason for this is the TextBox-based controls expect the data being dragged to be a string (i.e. System.String) or some other text-based type.  If I'm not mistaken, the RichTextBox also accepts other datatypes in the drag/drop such as Bitmap but I haven't looked into that at all.  If we provide our own custom drag/drop objects as we have here, the RichTextBox recognizes that a string is not being dragged and does not move the insertion point (although the text will drop in the right place when the mouse is released).

In order to trick the RichTextBox we must tell it that we're dragging a string, but drop something else...easier said than done.

We could create our own custom object that derives from IDataObject, but that gets messy and I'm not feeling particularly masochistic right now.  Instead, the developers of the .NET framework have given us a DataObject.  It is recommended that we use this object rather than implementing the IDataObject interface ourselves.

The DataObject object is used for both drag/drop operations as well as the clipboard.  I'm sure you're aware that the clipboard can contain items of varying types simultaneously; and that's the trick to getting this to work.  We need to not only add our KeywordItem instance to the DataObject, but also a string.

Now our code at the start of the drag operation resembles the following:

DataObject dragObj = new DataObject();
dragObj.SetData(””);   // add the string that will allow the RichTextBox to move the insertion point
dragObj.SetData(new KeywordItem(...));
DragDropEffects effects = this.DoDragDrop(dragObj, DragDropEffects.Copy);

I'd by lying if I said that the work is done.  As it turns out, the RichTextBox trumps our OnDragDrop(...) operation with a string present in the DataObject.  Though our code in the OnDragDrop() method runs, it will also drop the string we added to the DataObject.

Ok, so how do we work around this?  The solution I came up with is to allow the RichTextBox to accept the string (which is blank so it has no noticeable effect on the RichTextBox's contents) and add our text after the fact.  The easiest way to accomplish this is to use a timer with an almost imperceptible delay (such as 10-25 ms).

// temporary keyword storage for the data being
// dropped on the control from the toolbox

private KeywordItem _dragDropObj = null;

protected override void OnDragDrop(DragEventArgs e) {
   base.OnDragDrop(e);

   KeywordItem kw = (KeywordItem)e.Data.GetData(typeof(KeywordItem));
   if ( null != kw ) {
      _dragDropObj = kw;
      tmrDragDrop.Enabled = true;
   }
}

private void tmrDragDrop_Tick(object sender, EventArgs e) {
   tmrDragDrop.Enabled = false;

   switch ( _mode ) {
      // same as above except using _dragDropObj as keyword source...
   }
   _dragDropObj = null;
}

Tuesday, December 28, 2004 10:03:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

For years now I've employed a practice when evaluating (non)equality between a variable and a constant or null that continually comes under the scrutiny of my peers.  Once explained it's an eye opener, but it invariably gets a raised eyebrow at first glance.  It's a practice that I wish I could say that was an original idea, however, at least for my part, the credit goes to Dr. Peter J. Morris of The Mandelbrot Set (it appears that this site is not working anymore).

The idea is basically when performing a check for equality to order the expression with the variable on the right-side of the equality operator.  If you ever scan through my code you'll notice that it always resembles the following:

if ( 0 == x ) { ... }
if ( null == x ) { ... }
if ( fn() == x ) { ... }

I was sitting in a presentation by Dr Morris (Peet) and he entered all of his code in said manner.  I was intrigued (I did my own eyebrow raising).  What was the reasoning behind this?  Fortunately, I had the opportunity to sit down with him and talk about his presentation and asked him about it.

What is comes down to is simply elegant.  As I am an occasional C++ developer, the reasoning hit home with me.  Languages such as C++ allow you to perform the following without any warning or error from the compiler:

if ( x = 1 ) { ... }

If not intentional, the effect of this can be a very difficult to find bug.  First of all, the value '1' is assigned to the variable x.  Second, the expression is evaluated and deemed true because 1 is not 0 (or false).  Therefore, the if block is executed.  Note that if the expression had been if ( x = 0 ) { ... }, the block would never have run, but x would now have a value of 0.

Oftentimes, an expression such as this is a type-o...it should have been ==, so instead, had we written the expression thus:

if ( 1 = x ) { ... }

the compiler would have thrown a warning because we cannot change the value of a constant or function by assignment.  It's a safeguarding mechanism.

Fortunately (depending on your perspective), the .NET compilers disallow this operation to even compile because, for one reason or another, '1' is not a boolean expression...you MUST use the equality operator of ==.  Note that = is an assignment operator and == is an equality operator.

So why, if the C# compiler doesn't even allow it, do I continue on this syntactically burdensome path of reordering my expressions?  One reason is probably for the sake of consistency in code, but more importantly for me, it has also become the most natural way for me to write code.  In fact, I have extended the methodology (though unnecessarily) to the != operator simply for code clarity and uniformity.

However, the same is NOT true of the > and < operators.  It is much more natural to see and read

if ( x > 0 ) { ... }

rather than

if ( 0 < x ) { ... }

I'd rather understand the code at first glance than try to have to reason through a simple expression.

Am I crazy?  Does anyone else write code like this?

Tuesday, December 28, 2004 6:30:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [3]  |  Trackback
 Monday, December 27, 2004

I was in the process of writing some code that extended the functionality of the OnKeyPress() method of a TextBox (RichTextBox to be precise).  This code has the need not only to validate text as it is entered, but also to perform certain actions based on whether certain keystrokes are made within it.  The OnKeyPress() method receives as it's parameter a KeyPressEventArgs object indicating the key that was pressed.  It does not, however, contain any information as to whether the CTRL, SHIFT, or ALT keys are pressed - that information is reserved for the OnKeyDown() and OnKeyUp() methods.

Being the in-a-past-life-Win32 developer that I am, my first inclination was to write the following code:

[DllImport(“user32.dll“)]
private static extern Int16 GetKeyState(Int32 nVirtKey);
private const int VK_CONTROL = 0x11;

And then within the OnKeyPress() method:

bool ctrl = ( ( GetKeyState(VK_CONTROL) & 0x8000 ) > 0 );
if ( ctrl ) {
   //...
}

This, however, seemed too un-.NET-ish.  Therefore, I started to investigate.  It didn't take long however, and I found what I was looking for.  It turns out the Control class exposes a static method called ModifierKeys that indicates the state of the CTRL, SHIFT, and ALT keys.  My code suddenly became much cleaner and w/o the need to use P/Invoke to get the data I wanted:

if ( Keys.Control == Control.ModifierKeys ) {
   //...
}

Monday, December 27, 2004 9:47:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Friday, December 17, 2004

In my previous life (pre-.NET), I devoted a lot of time to being a component/control developer and therefore became intimately familiar with the GDI and the WinAPI in general.  One of the critical functions to be aware of is the DrawEdge GDI function.  This method provides the mechanism that the OS uses to render the three-dimensional edges for controls in the system (buttons, textboxes, frames, etc).

When you make the transition to .NET, however, the DrawEdge function is nowhere to be found.  Sure, you can DllImport the thing and call it natively via P/Invoke, but I want native, framework support.  As it turns out, you can call the DrawEdge function with built-in framework support, but it's not where you might expect it.

Within the System.Drawing namespace there is a class called ControlPaint that consists entirely of static methods.  These methods enable the developer to render your typical UI features such as buttons, checkboxes, grab handles, focus rectangles, etc.  It's nice that all of these functions are placed in one easy-to-get-to place.  The replacement(s) for the DrawEdge function are DrawBorder and DrawBorder3D.  At first I wondered as to why there was no DrawEdge function on the Graphics object.  It would be so convenient to have code like e.Graphics.DrawEdge(...) in the OnPaint(), but then I got to thinking about it and it makes so much more sense to have UI-related rendering methods consolidated into their own class.

I'm in the process of creating a toolbox control not dissimilar to that within VS.NET, but not as fully featured either.  This control needs the ability to dynamically have controls (labels) added to it and I wanted to track mouse events on each label, displaying a slightly 'popped-up' edge.  Here's a real quick class that I created (I literally wrote it in about 30 seconds) that accomplishes this with minimal code.  Sure, I'll flesh it out a bit more to get exactly the behavior I want, but it's just roughed out so far.

internal class LabelTool : Label {
   private bool _mouseOver = false;

   protected override void OnMouseEnter(EventArgs e) {
      base.OnMouseEnter(e);
      _mouseOver = true;
      this.Invalidate();
   }

   protected override void OnMouseLeave(EventArgs e) {
      base.OnMouseLeave(e);
      _mouseOver = false;
      this.Invalidate();
   }

   protected override void OnPaint(PaintEventArgs e) {
      base.OnPaint(e);
      if ( _mouseOver ) ControlPaint.DrawBorder3D(e.Graphics, this.ClientRectangle, Border3DStyle.RaisedInner);
   }
}

Friday, December 17, 2004 7:00:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Wednesday, December 15, 2004

Here's a cool little quiz that a friend shared with me.  Test your knowledge of the geography of the United States of America.

First (and only attempt): Score 94%, Avg Error: 9 miles, Time: 563 seconds.

Update 07/26/2005:  On a whim, I thought I'd try it again.  Including one accidental slip of the mouse, my new results:
Score: 96%, Avg Error: 5 miles, Time: 383 seconds

Wednesday, December 15, 2004 11:53:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Monday, December 13, 2004

Call me late to the party.  I know there was a lot of hype about the show when it aired a few years ago, but I literally watch less that 30 minutes of TV a week (besides a few select sporting events involving the University of Utah Utes Football team and a few other choice selections).  A good friend of mine, lent me Season 1 and Season 2 of “24”.  Oh my goodness I am hooked!  I've had the opportunity to watch about 4 episodes a night (1 dvd/night) and I'm dying to see the next four episodes.  So far I'm half way through the first season, having arrived at 12:00 pm and I'm anxiously awaiting tomorrow night when I can find out what happens next.

In all honesty, I'm kinda glad I've waited until now to see them, after the hype has passed so I can relive the excitement again - without any commercials and having the cliff-hanger that lasts a week.  Now the cliff-hanger lasts about 20 seconds (or at most one day).

Well, I just wanted to share my 'discovery'.  I am delighted to watch such rivetting, high-quality programming.  I haven't had this much fun following a program since the X-Files.

Monday, December 13, 2004 6:27:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [1]  |  Trackback
 Friday, December 10, 2004

A good friend of mine, Scott Golightly, is now blogging!  Employed at Keane, Inc, Scott has been a consultant for over 12 years.  As an alter-ego, Scott parades around as our local Microsoft Regional Director, giving the occasional talk at the .NET User Group or even speaking at Tech Ed.

Glad you joined the blog party!  Welcome aboard!

Friday, December 10, 2004 5:10:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback

Just last night I had need to create a server-side repeater control programmatically.  This is something that, thus far, I have not had much need to do.  Most of the time, I've resorted to embedding <asp:repeater /> controls (or some other control such as a DataList or a DataGrid) on an .aspx or .ascx control and establishing templates as in the following:

<ul>
<asp:repeater id=repeater runat=server>
   <itemtemplate>
   <li><%# DataBinder.Eval(Container.DataItem, "DataField")%></li>
   </itemtemplate>
</asp:repeater>
</ul>

This, I believe, is a pretty popular route that developers take.  My circumstances, however, proved to be different this time.  I needed to create a server control (derived from WebControl) that utilized a templated Repeater control.  The trick here wasn't so much getting a Repeater control on the page, but rather to create a data-bindable template without the 'code-in-front'.

This was, in fact, extremely easy to accomplish despite all of the useless help examples in MSDN.  In fact the MSDN help only added hot coals to the fire of confusion so I abandoned it to figure it out manually.

Basically, what it came down to was that I had to create a class that derived from ITemplate and assign an instance of this class to the ItemTemplate, AlternatingItemTemplate, or whatever property of the Repeater control.  By implementing the ITemplate.InstantiateIn() method, we provide the runtime the opportunity to hook our template into the proper parent control.  In order to render the output html we have to use server controls (such as the Literal control) because we cannot add plain text directly to the Controls collection of the parent control.

That's all there is to it to create a simple template, but for the most part that isn't enough.  One of the most powerful and luring capabilities of templates is their ability to data bind.  In this case we cannot simply embed the databinding tags <%#...%> within our text because those expressions are parsed out of an .aspx/.ascx and turned to code before the template is ever created.  Therefore, in order to accomplish this, we must attach to the DataBinding event of the control outputting the data (the Literal control in our case).  This is where things get a bit more involved - but not by much.

The DataBinding event has the signature of a typical EventHandler (object sender, EventArgs e).  The sender parameter can be cast to the Literal control as it is the control on which the event is firing.  Then, to get at the data that is being bound to our template instance we must acquire a reference to the RepeaterItem (because we're dealing with a Repeater control).  The RepeaterItem has a property called DataItem from which we can extract the data being bound.  After that, it's merely a matter of dumping the data to the control.

Suppose that we had the following Customer class:

public class Customer {
   private string _id;
   private string _name;
  
   public Customer(string id, string name) {
      _id = id;
      _name = name;
   }
  
   public string Id {
      get { return _id; }
      set { _id = value; }
   }
  
   public string Name {
      get { return _name; }
      set { _name = value; }
   }
}

Now an array of Customer instances will be provided to the fictitious control for data binding.  Our control might resemble the following in the server-side code:

public class CustomerListing : WebControl {
   private Repeater repeater;
  
   protected override void OnInit(EventArgs e) {
      base.OnInit(e);
     
      // create the repeater
      repeater = new Repeater();
      this.Controls.Add(repeater);
     
      // assign the template instance to the repeater
      repeater.ItemTemplate = new CustomerTemplate();
   }
  
  
   protected override void OnLoad(EventArgs e) {
      base.OnLoad(e);
     
      Customer[] customers = BusinessLayerSomethingOrOther.GetCustomers();
      repeater.DataSource = customers;
      repeater.DataBind();
   }
  
  
   protected override void Render(HtmlTextWriter writer) {
      writer.Write("<b>Customer List</b>");
      writer.Write("<ul>");
      base.Render(writer);
      writer.Write("</ul>");
   }
}

Now it's time to get into the template.

internal class CustomerTemplate : ITemplate {
   Literal lit;
  
   void ITemplate.InstantiateIn(Control container) {
      lit = new Literal();
      lit.DataBinding += new EventHandler(dataBind);
      container.Controls.Add(lit);
   }
  
  
   private void dataBind(object sender, EventArgs e) {
      // get a reference to the Literal control
      Literal lit = sender as Literal;
      // get a reference to the templated item
      RepeaterItem container = lit.NamingContainer as RepeaterItem;
      // note: we could use DataBinder.Eval(...) but I'd rather not take the perf hit
      Customer cust = ((Customer)container.DataItem);
      lit.Text = string.Format("<li>{0} - {1}</li>", cust.Id, cust.Name);
   }
}

As you can see, it's pretty easy to accomplish this!  There is so much more than can be accomplished, but this is merely a first step into the greater world of server-side templating.

Friday, December 10, 2004 4:16:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [14]  |  Trackback

Boy!  This has been a slow month for blogging!  I've been travelling so much and working so hard that once again my blog has become secondary.

I am out of town at the moment and regrettably missed our .NET User Group meeting last night.  My good friend and associate, Matt Smith, from our local Salt Lake City Microsoft offices gave what I'm sure was a excellent talk on Sql Server Reporting Services - Matt never fails to impress me on any level.  As perhaps one of the best developers I have ever met, I'm always impressed.

In my experience, I routinely run into developers that have never even heard of SRS which is regrettable.  I hope that the presentation was not only an eye-opener but replete with technical goodies that developers crave.

Friday, December 10, 2004 3:28:00 AM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback
 Thursday, December 02, 2004

This hit me pretty good today - it took about an hour and a half to solve.  The whole time I spent almost pulling my hair out...though I did have a glass of apple juice which whet the appetite nicely.

Ever since I removed myself from my local Administrators group, I've been wanting to test a particular website that I developed (and have been developing for some time).  The website uses impersonation, thereby allowing me to effectively run as a different user.  I didn't want, even for testing/development purposes, to have direct access to databases or other objects.  Rather I've wanted to write the software in an environment more like the one into which it will be deployed.

Well, because I removed myself from the Administrators group, I have had to run ASP.NET as a user other than ASPNET in order to debug the websites.  Of course, this was not a problem at all.  I simply encrypted my credentials via aspnet_setreg.exe and updated the machine.config file's to point to the registry as the source for its credentials.  All has been great - until today, well, yesterday, but that's a different story all together.

Upon attempting to run this website, I was greeted with the not-so-friendly-but-somewhat-informative message of “Access Denied to 'C:\...\Index.aspx'.  Failed to start monitoring file changes.” Therefore, I attempted to run the project from within Visual Studio, to see if I could further debug the problem and isolate any issues.  I got a different message all together: “Configuration Error.  Unable to load c:\windows\...\machine.config.  Either a required impersonation level was not provided, or the provided impersonation level is invalid.”

This seemed a simple, permissions settings.  I proceeded, therefore, to grant my impersonated user rights to the folders and files in question.  No dice.  Same message.  Hmmm, this was getting interesting - and a tad frustrating.

I tried granting the user Full Control at the root C:\ level to see if that took care of things - a big fat nope!

Interestingly, if I set the impersonated user to be my domain administrator it still didn't work.  It ONLY worked under my account.  Then I started to think - I probably don't have rights to impersonate.  When I was in the Administrators group I had that right by membership, but now that I'm a lowly User, that privilege had been stripped.

The solution?  Well, I opened my Local Security Policy (running it as the administrator), expanded Local Policies\User Rights Assignment and navigated to the 'Impersonate a client after authentication' policy setting.  Sure enough only three accounts by default were granted this right:  Administrators, ASPNET, and SERVICE.  I simply had to add my account (because that's the account the ASP worker process is running as) to the list.  Then I opened the command prompt and ran gpupdate /force to ensure that all policy changes took effect, then ran iisreset.

Now it works and I'm ready to ride off into the sunset and retire - at least for the evening.

Thursday, December 02, 2004 6:12:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [14]  |  Trackback
 Wednesday, December 01, 2004

It just goes to show you!  When you feel you know and understand a product pretty well, some new nook or cranny appears, allowing you into previously unexplored territories.

I never had explored this facet of IE, but Nikhil Kothari identifies that you can create your own stylesheets and apply them to Internet Explorer in general.  Specifically, he points out simply enlarging (zooming) the contents of the browser by creating a simple stylesheet containing nothing but body { zoom: xxx% }.  This is fantastic - especially for presentations!

One thing of note, because I had never looked into the zoom attribute before:  not only does it enlarge what the browser is presenting (text, images), but also its scrollbars.  Likewise, it does not zoom contents for which HTML (for one reason or another in IE) has no control over, such as your caret or combo boxes.

Additionally, this stylesheet, should you choose to apply it, affects ALL Internet Explorer-based applications on your system universally (Outlook, Web Browser controls, etc), so choose your styles with care.

Wednesday, December 01, 2004 2:09:00 PM (Mountain Standard Time, UTC-07:00)  #    Disclaimer  |  Comments [0]  |  Trackback