Thursday, February 25, 2010

Another Way to Think about Code Reuse

Anyone who practices Object Oriented Programming has a lot of different ways to reuse code. The most common way is to use inheritance, but recently I have been reusing code in an unconventional way.

Whenever I create a class I follow a strict convention on naming properties. Here is an example:

  1. public class Movie
  2. {
  3.     public string Title { get; set; }
  4.     public List<People> Actors { get; set; }
  6.     public DateTime ReleaseDate { get; set; }
  7.     public double MoneyEarnedToDate { get; set; }
  9.     public string Producer { get; set; }
  10.     public string Genre { get; set; }
  11. }

CamelCase is the convention I use to define every property. I always use complete words and never use abbreviations. I do not use underscores in public properties. I stick to this convention because it lets me extract Meta data from the class while it is in use and can be used to simplify coding of the UI.

  1. public class CustomGrid : DataGrid
  2. {
  3.     public CustomGrid()
  4.         : base()
  5.     {
  6.         AutoGenerateColumns = true;
  7.         AutoGeneratingColumn += new EventHandler<DataGridAutoGeneratingColumnEventArgs>(OnAutoGeneratingColumn);
  8.     }
  10.     void OnAutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
  11.     {
  12.         string sHeader = e.Column.Header.ToString();
  13.         e.Column.Header = CamelToTitleCase(sHeader);
  14.     }
  16.     public string CamelToTitleCase(string Text)
  17.     {
  18.         Text = Text.Substring(0, 1).ToUpper() + Text.Substring(1);
  19.         return Regex.Replace(Text, @"(\B[A-Z])", @" $1");
  20.     }
  22. }

Via inheritance I can customize the standard Silverlight DataGrid to automatically generate columns for whatever class is bound to it. I sign up for the OnAutoGeneratingColumn event so I can rename the column headings. The function CamelToTitleCase will automatically insert spaces before each capitol letter, so the property ReleaseDate becomes the header Release Date and the property MoneyEarnedToDate becomes Money Earned To Date

So is using a coding convention really code reuse or is it more like asset repurposing? I have learned that having a convention makes my code easier to read and debug. It also leads to even more advanced techniques I will share in later blogs.

Monday, February 15, 2010

Know Your Parents and Grandparents

In programming Silverlight I have come across situations where a control or framework element needs to access information on its parent. The code to get information off your direct parent is simple:

  1.             var oContent = this.Parent.ReadLocalValue(Content);
for example.

The real power of Silverlight is in the declarative nesting of XAML elements, and that means that the type of your direct parent may not always be known. To clarify, if you drop a control on a Page, then the Page object will be your parent. However if you then wrap your control in a ScrollViewer, the ScrollViewer becomes your parent and the Page becomes your grandparent.

To avoid all these issues I include the following code in most of my Silverlight projects:

  1.         public virtual T ParentOfType<T>() where T : FrameworkElement
  2.         {
  3.             Type oType = typeof(T);
  4.             var oParent = Parent as FrameworkElement;
  5.             while (oParent != null)
  6.             {
  7.                 if (oType.IsInstanceOfType(oParent))
  8.                     return oParent as T;
  10.                 if (oParent.GetType() == oType)
  11.                     return oParent as T;
  13.                 oParent = oParent.Parent as FrameworkElement;
  14.             }
  15.             return null;
  16.         }

Recently I needed to access the Navigation Service that is part of a Silverlight Page object. Using the method above I wrote this code to access the service:

  1.         void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  2.         {
  3.             var oPage = ParentOfType<Page>();
  5.             if ( oPage != null )
  6.                 oPage.NavigationService.Navigate(new Uri(NavigateUri, UriKind.RelativeOrAbsolute));
  7.         }

Now regardless where this control is placed in the XAML, the Navigation Service will execute correctly.