My full posts with examples

-July 2010+
SMTWTFS
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

  • RSS
  • Add To My MSN
  • Add To Windows Live
  • Add To My Yahoo
  • Add To Google

Statistics

  • Entries (3)
  • Comments (6)

Categories

How to make a CheckBox fire the ItemCommand Event of a Repeater 

Thursday, October 22, 2009 9:54:39 PM
Rate this Content 0 Votes





At work today I tried to do something I though would be simple, I needed to add a check box control to a repeater's item template and have it fire the ItemCommand event on the repeater.  The button and link button controls do this without a problem but for some reason Microsoft decided that the check box was going to be different.  Luckily we have great tools like Reflector to help in situations like this, if you dig into the Repeater's source code you will find out that the ItemCommand event gets fired by event bubbling.  When you add a button or link button to a repeaters template and click on it it will eventually run this code as part of it's post back.

   1: protected virtual void RaisePostBackEvent(string eventArgument)
   2: {
   3:     base.ValidateEvent(this.UniqueID, eventArgument);
   4:     if (this.CausesValidation)
   5:     {
   6:         this.Page.Validate(this.ValidationGroup);
   7:     }
   8:     this.OnClick(EventArgs.Empty);
   9:     this.OnCommand(new CommandEventArgs(this.CommandName, this.CommandArgument));
  10: }
  11:  

Notice how the last line in this code calls "this.OnCommand" and passes a CommandEventArgs instance with command name and command argument.  The button and link button have this extra code while the checkbox does not.  The code for this method looks like this:

   1: protected virtual void OnCommand(CommandEventArgs e)
   2: {
   3:     CommandEventHandler handler = (CommandEventHandler) base.Events[EventCommand];
   4:     if (handler != null)
   5:     {
   6:         handler(this, e);
   7:     }
   8:     base.RaiseBubbleEvent(this, e);
   9: }
  10:  
  11:  

All the magic that makes the button and link button work is right here.  Calling "base.RaiseBubbleEvent" and passing it the same CommandEventArgs from above allows the repeater control to catch this event later on in its OnBubbleEvent.  The on bubble event for the repeater looks like this:

   1: protected override bool OnBubbleEvent(object sender, EventArgs e)
   2: {
   3:     bool flag = false;
   4:     if (e is RepeaterCommandEventArgs)
   5:     {
   6:         this.OnItemCommand((RepeaterCommandEventArgs) e);
   7:         flag = true;
   8:     }
   9:     return flag;
  10: }
  11:  

The ItemCommand event is only fired here and only if the eventargs type is RepeaterCommandEventArgs.  Since the standard CheckBox control does not call the RaiseBubbleEvent like a button or link button it's checkchanged event will never make it here.  But there is a very simple solution to make it work this way, all you have to do is create a custom checkbox control that calls RaiseBubbleEvent during it's OnCheckChanged event.  Here is a an example, this CheckBoxRepeaterAware control is the same as a regular CheckBox except for the addition of two properties and an overridden OnCheckChanged event. 

   1: public class CheckBoxRepeaterAware : CheckBox
   2:     {
   3:         #region Properties
   4:  
   5:         #region CommandName
   6:  
   7:         public string CommandName
   8:         {
   9:             get
  10:             {
  11:                 if (this.ViewState["CommandName"] == null)
  12:                 {
  13:                     return string.Empty;
  14:                 }
  15:                 else
  16:                 {
  17:                     return this.ViewState["CommandName"] as string;
  18:                 }
  19:             }
  20:             set
  21:             {
  22:                 this.ViewState["CommandName"] = value;
  23:             }
  24:         }
  25:  
  26:         #endregion
  27:  
  28:         #region CommandArgument
  29:  
  30:         public string CommandArgument
  31:         {
  32:             get
  33:             {
  34:                 if (this.ViewState["CommandArgument"] == null)
  35:                 {
  36:                     return string.Empty;
  37:                 }
  38:                 else
  39:                 {
  40:                     return this.ViewState["CommandArgument"] as string;
  41:                 }
  42:             }
  43:             set
  44:             {
  45:                 this.ViewState["CommandArgument"] = value;
  46:             }
  47:         }
  48:  
  49:         #endregion
  50:  
  51:         #endregion
  52:  
  53:         #region Procedures
  54:  
  55:         #region On Checked Changed
  56:  
  57:         protected override void OnCheckedChanged(EventArgs e)
  58:         {
  59:             //create a new event args of type command event args
  60:             CommandEventArgs ce = new CommandEventArgs(this.CommandName, this.CommandArgument);
  61:  
  62:             //allow the base checkbox to handle the event as normal
  63:             base.OnCheckedChanged(e);
  64:  
  65:             //raise the contorls method RaiseBubbleEvent
  66:             base.RaiseBubbleEvent(this, ce);
  67:  
  68:         }
  69:         #endregion
  70:  
  71:  
  72:         #endregion
  73:  
  74:     }

As you can tell, in the OnCheckChanged event we are calling "base.RaiseBubbleEvent" and passing it the command name and command argument.  By doing this, the repeater will be able to fire it's ItemCommand event for us.  Again, I am not sure why Microsoft didn't just implement this in the first place for the check box control but at least the framework is flexible enough that we can do it now.  The last thing we need to do to make this solution even easier is add a tag mapping in our web config to allow the new CheckBoxRepeaterAware control to replace all instances of CheckBox controls in our application.  To do that we add the following to the web config inside the pages node:

   1: <tagMapping>
   2:     <add tagType="System.Web.UI.WebControls.CheckBox" mappedTagType="CheckBoxRepeaterAwareDemo.Classes.CheckBoxRepeaterAware"/>
   3: </tagMapping>

I made a sample project where you can see it working in action, download the sample code here.

Exception handling with generics and a common result class 

Thursday, October 22, 2009 9:51:29 PM
Rate this Content 0 Votes





For some time now, I have been using a pattern I call “Common Function Result” to deal with errors and return values from functions. When I first learned about .Net and learned about try/catch blocks, I thought they were great. I thought they were leaps and bounds above the classic VB OnError mechanism, but they still didn’t solve all my problems. I wanted a cleaner way to get the error information from the function back to the caller. After some trial and error I came up with this class:

   1: public class FunctionResult<returnType>
   2: {
   3:  
   4: #region Properties
   5:  
   6: #region "ExceptionVal"
   7:  
   8: private Exception _exceptionVal = null;
   9: /// <summary>
  10: /// Gets or sets the exception val.
  11: /// </summary>
  12: /// <value>The exception val.</value>
  13: public Exception ExceptionVal
  14: {
  15:     get
  16:     {
  17:         return this._exceptionVal;
  18:     }
  19:     set
  20:     {
  21:         this._exceptionVal = value;
  22:     }
  23: }
  24:  
  25: #endregion
  26:  
  27: #region "ReturnVal"
  28:  
  29: private returnType _ReturnVal = null;
  30: /// <summary>
  31: /// Gets or sets the return val.
  32: /// </summary>
  33: /// <value>The return val.</value>
  34: public returnType ReturnVal
  35: {
  36:     get
  37:     {
  38:         return this._ReturnVal;
  39:     }
  40:     set
  41:     {
  42:         this._ReturnVal = value;
  43:     }
  44: }
  45:  
  46: #endregion
  47:  
  48: #region "ResultType"
  49:  
  50: private FunctionResultTypes _ResultType = null;
  51:  
  52: /// <summary>
  53: /// Gets or sets the type of the result.
  54: /// </summary>
  55: /// <value>The type of the result.</value>
  56: public FunctionResultTypes ResultType
  57: {
  58:     get
  59:     {
  60:         return this._ResultType;
  61:     }
  62:     set
  63:     {
  64:         this._ResultType = value;
  65:     }
  66: }
  67:  
  68: #endregion
  69: #endregion
  70:  
  71: }
  72: #region Supporting Classes
  73:  
  74: /// <summary>
  75: /// List of possible errors that can be return from a function result
  76: /// </summary>
  77:  
  78: public enum FunctionResultTypes
  79: {
  80:     /// <summary>
  81:     /// The function result was sucessful.
  82:     /// </summary>
  83:     NoErrors = 1,
  84:     
  85:     /// <summary>
  86:     /// The function result encountered validation errors.
  87:     /// </summary>
  88:     ValidationErrors = 2,
  89:  
  90:     /// <summary>
  91:     /// The function result encountered unexpected errors.
  92:     /// </summary>
  93:     OtherErrors = 3
  94:  
  95: }
  96:  
  97: #endregion

This class is the heart of the pattern. Instead of returning the actual result type from a function I am writing like string or int, I return this class which has these three properties: ResultType, ReturnVal, and ExceptionVal. For instance, let’s say I am writing the following function:

   1: public int divideSomeNumbers(int numberOne, int numberTwo)
   2: {
   3:     if (numberOne == 0 || numberTwo == 0)
   4:     {
   5:         throw new Exception("Value can't be zero");
   6:     }
   7:  
   8:     return numberOne / numberTwo;
   9: }

This function is pretty simple; it takes two numbers and divides them, it also does some error checking to make sure that neither of the passed in numbers is zero. To let the caller know that one of the numbers that was passed in is equal to zero, it throws an exception. To make this function use the pattern I would rewrite it like this:

   1: public FunctionResult<int> divideSomeNumbers(int numberOne, int numberTwo)
   2: {
   3:     FunctionResult<int> ret = new FunctionResult<int>();
   4:  
   5:     try
   6:     {
   7:         if (numberOne == 0 || numberTwo == 0)
   8:         {
   9:             ret._ResultType = FunctionResultTypes.ValidationErrors;
  10:             ret._exceptionVal = new Exception("Value can't be zero");
  11:             return ret;
  12:         }
  13:  
  14:         ret._ReturnVal = numberOne / numberTwo;
  15:         ret._ResultType = FunctionResultTypes.NoErrors;
  16:  
  17:     }
  18:     catch(Exception e)
  19:     {
  20:         ret._exceptionVal = e;
  21:         ret._ResultType = FunctionResultTypes.OtherErrors;
  22:     }
  23:  
  24:     return ret;
  25:  
  26: }

The new version of the function always returns something to the caller so the caller does not need to worry about wrapping their call in a try/catch block; all they need to do is check the ResultType property and see if there was an error. If there was an error, the caller then has the option to retrieve the exception from the ExceptionVal property and do something with it, like display the error message. If there was not an error then the caller can use the ReturnVal property to get the actually function result. Since the ReturnVal property uses generics, the caller will get the strongly typed result back from the function. Here is an example of code to call the new version of the function:

   1: FunctionResult<int> ret = divideSomeNumbers(0, 1);
   2:  
   3: switch(ret.ResultType)
   4:  
   5: {
   6:  
   7:     case FunctionResultTypes.NoErrors:
   8:  
   9:         Console.Write(string.Format("The function result was {0}", ret.ReturnVal.ToString()));
  10:  
  11:         break;
  12:  
  13:     case FunctionResultTypes.ValidationErrors:
  14:  
  15:         Console.Write(string.Format("There was a validation error: {0}", ret.ExceptionVal.Message));
  16:     
  17:         break;
  18:  
  19:     case FunctionResultTypes.OtherErrors:
  20:  
  21:         Console.Write(string.Format("The function had an unexpected error: {0}", ret.ExceptionVal.Message));
  22:  
  23:         break;
  24:         
  25: }
  26:  

To me, the code above is cleaner and much easier to read. It also lets you handle different types of errors like validation and unexpected exceptions in a common way.

How to use a ConfigurationElementCollection with custom attributes 

Thursday, October 22, 2009 9:49:36 PM
Rate this Content 0 Votes





The other day I was working on a utility class that did xslt transformations and I wanted to make it read some file paths from the app/web.config file.  I found some great examples on the web about using custom configuration sections for .Net 2.0 (just seach google for "custom config sections") but then I hit a road block when I wanted my config section to look like this:

<XSLTTransformDefinitions>    <-- Inherits ConfigurationSection         
         <TransformGroups>       <-- Inherits ConfigurationElementCollection         
                 <TransformGroup GroupName="Foo">    <-- Inherits ConfigurationElementCollection

                  <Transforms>         
                          <Transform Name="Foo1" FilePath="aklsdjf"/>  <-- Inherits ConfigurationElement
                          <Transform Name="Foo2" FilePath="asdfjalsd;fj"/>
                          <Transform Name="Foo3" FilePath="alsjfajklsd"/>
                 </Transforms>
                 <Transforms GroupName="Bar">
                          <Transform Name="Bar1" FilePath="aklsdjf"/>
                          <Transform Name="Bar2" FilePath="asdfjalsd;fj"/>
                 </Transforms>

             </TransformGroup>
         </TransformGroups>
</XSLTTransformDefinitions>

Everything was going great until i realized that I needed to have two layers of collections, I needed my first collection (TransformGroup) to have an attribute that I could use as an identification key later on in the code.  No matter what I did I could not get the configuration manager to read the custom attribute on the "TransformGroup" configurationelementcollection.  When you want a property read by the configuration manager during the GetSection call you are suppose to just add the "ConfigurationProperty" attribute to your property statement in your class like so:

<ConfigurationProperty("Name", IsKey:=True, isrequired:=True)> _
Public Property Name() As String
         Get
                Return DirectCast(Me("Name"), String)
         End Get
         Set(ByVal value As String)
                Me("Name") = value
         End Set
End Property      

This works fine when you inherit from the configurationelement and you get access to the base collection via the Me("SomeAttributeName") statements  but when you try the same thing in a class that inherits from configurationelementcollection you get an error because the base collection contains in this case "Transform" elements, not attributes read from the element.  After some time of searching and a little bit of trial and error I figured out a hack.  What you have to do is use the "OnDeserializeUnrecognizedAttribute" method.  You can override this method in you class and when the configuration manager finds any attributes on your xml that are not defined by a class somewhere it calls this method allowing you to do something with what it found.  For my solution I just created a property on my "TransformGroup" class called group name and did not add any code attributes to it, then I overrided the method like this:

Protected Overrides Function OnDeserializeUnrecognizedAttribute(ByVal name As String, ByVal value As String) As Boolean
        If (name = "GroupName") Then
               Me._GroupName = value
               Return True
        End If
        Return MyBase.OnDeserializeUnrecognizedAttribute(name, value)
End Function

It is a bit of a hack but it works.  All you have to do is return true from this function, otherwise .Net will throw an exception.