Friday, March 29, 2013

Disable DotNetNuke 7 styling for checkboxes and radio lists

DNN7 replaces input checkbox and radio list controls with custom styling.  For checkboxes, the original checkbox input is hidden and replaced in the UI with an image.  Furthermore the DNN functionality breaks when the input checkbox is rendered by a repeater (e.g., within a table row), making the checkbox unusable.

The method that causes the DNN functionality for checkboxes and radio list controls is declared in dnn.jquery.js and is called $.fn.dnnCheckbox
Here are four possible solutions:

  • Delete the content of the $.fn.dnnCheckbox function declared in dnn.jquery.js (located in \Resources\Shared\scripts).  The problem with this approach is a DNN site upgrade will restore the DNN functionality.
  • Put this script block in the page header after dnn.jquery.js is loaded:
  1. <script type="text/javascript">
  2.     (function () {
  3.         $(document).ready(function () {
  4.             $.fn.dnnCheckbox = function (options) { };
  5.         });
  6.     }());
  7. </script>
  • Run this script after the checkbox control has rendered:
  1. function RemoveDnnCheckboxFormat() {
  2.     $('.dnnCheckbox').remove();
  3.     $(':checkbox').removeAttr('style');
  4. }
  • (updated - thanks to comments from Anonymous) Add the class “normalCheckBox” or “normalRadioButton” to CheckBox or RadioButtonList controls, respectively.

Thursday, March 21, 2013

Lookup table design for Entity Framework Code First

I’ve been learning Entity Framework Code First and would like to share a design I developed for Lookup tables.  The project requirement is to make reporting as easy as possible for the client because they will be writing all of their own queries and reports, however I want to leverage lookup tables in my entities and also protect the client from data issues do to misspellings.  Therefore I designed my lookup tables to have the value field also be the PK/FK and I added an enumerator field to support compile integrity in my code.  Note that Entity Framework 5 is required for enumerator support in Code First.

I defined a common base class for all of my lookup table POCO classes:

  1. public abstract class LookupModel<TEnum> : ILookupModel
  2. {
  3.     [Key, MaxLength(50)]
  4.     public string Value { get; set; }
  5.  
  6.     public TEnum ValueCode { get; set; }
  7. }

Here is an example implementation for a Gender lookup POCO class:

  1. [Table("Genders")]
  2. public class GenderLookup : LookupModel<Gender>
  3. {
  4.     public GenderLookup() {}
  5. }

I defined a Gender enum with some extension methods for sorting and for translating between the database values and the enumerated values.

  1. public enum Gender
  2. {
  3.     NA = 0, Male, Female
  4. }
  5.  
  6. public static class GenderExtensions
  7. {
  8.     public static int SortOrder(this Gender value)
  9.     {
  10.         switch (value)
  11.         {
  12.             case Gender.Male:
  13.                 return 1;
  14.             case Gender.Female:
  15.                 return 2;
  16.             case Gender.NA:
  17.                 return int.MinValue;
  18.             default:
  19.                 throw new ArgumentException("Invalid Gender value '" + value.ToString() + "'");
  20.         }
  21.     }
  22.     public static string ToDatabaseValue(this Gender value)
  23.     {
  24.         switch (value)
  25.         {
  26.             case Gender.Male:
  27.                 return "Male";
  28.             case Gender.Female:
  29.                 return "Female";
  30.             case Gender.NA:
  31.                 return null;
  32.             default:
  33.                 throw new ArgumentException("Invalid Gender value '" + value.ToString() + "'");
  34.         }
  35.     }
  36.     public static Gender ToGenderFromDatabaseValue(this string value)
  37.     {
  38.         foreach (Gender key in Enum.GetValues(typeof(Gender)))
  39.         {
  40.             if (string.Compare(value, key.ToDatabaseValue(), true) == 0)
  41.                 return key;
  42.         }
  43.         return Gender.NA;
  44.     }
  45. }

Seeding the Genders table is made simple by looping through the Gender enumerator:

  1. internal static List<GenderLookup> SeedGenders(Context context)
  2. {
  3.     List<GenderLookup> luList = new List<GenderLookup>();
  4.     foreach (Gender key in Enum.GetValues(typeof(Gender)))
  5.     {
  6.         if (key != Gender.NA)
  7.             luList.Add(new GenderLookup() { Value = key.ToDatabaseValue(), ValueCode = key });
  8.     }
  9.     context.Genders.AddOrUpdate(lu => lu.Value, luList.ToArray());
  10.     return luList;
  11. }

Including the enumerated property on my POCO makes LINQ queries a breeze:

  1. private static GenderLookup GetMaleGender(System.Data.Entity.DbContext context)
  2. {
  3.     return context.Set<GenderLookup>().First(l => l.ValueCode == Gender.Male);
  4. }