My struggles in understanding and learning about Object Oriented design, and the tools and knowledge I've taken from them.

Friday, January 22, 2010

Inheriting from .Net base controls

.Net Controls (and their Win32 ancestors), such as TextBox, ComboBox, DataGridView, etc, were built to be decoupled from any one application; they have to be.  These controls need to be used by tens or hundreds of thousands of developers building any number of types of applications.

The trouble with generic, decoupled code (and APIs) is that it is so loosely coupled from the rest of the application, that it takes finangling to get the loosely coupled code to work with the rest of your tightly coupled code.

This is a case study in inheritance, and my guess is that most software engineers use inheritance to build custom controls (or build their own controls, or purchase them from external vendors, such as SyncFusion).  For the context of this blog, I'll simply address using inheritance to extend base .Net classes for your own purposes.

When building a class (in this case, a Control), there are 3 strategies one can use to look at the class:
1.  Set all attributes, and interact with class behavior from outside of the class
2.  Set all attributes, and interact with class behavior from inside of the class
3.  Do some combination of 1 and 2.

Most code falls into category #3, as is the appropriate thing to do.  In the case of Controls (and many other code constructs, as well), the difference between tightly coupled code and loosely coupled code is what percentage of behavior is set from outside of the class, versus what percentage is set from within the class.  Another component of the tightly versus loosely coupled code is how much the code knows about the data structures and code that you've built into your application.

In the case of .Net controls, the controls don't, by default, know anything at all about the classes in your application; that is the trade-off you make with extending base control behavior:  the custom controls know about your code, but those controls are probably going to be meaningless outside of your code base because they have become so tightly coupled to your architecture.

So, on to an example.  Consider a DataGridView control.  Typically, if using the base .Net DataGridView, you instantiated it, put it on a control, and set the data source.  The setting of the data source is the "doing work from outside of the class."  Suppose you want to transfer that responsibility to the class.  You could extend the class as follows:


class CustomDataGridView : System.Windows.Forms.DataGridView
{
   public CustomDataGridView(DataTable dataSource)
    {

       ///Set the base data source to the passed
       //DataTable parameter

         base.DataSource = dataSource;

   }
}


The above is a simple example, but suppose you wanted multiple controls to behave in a similar way.  Since all controls have different behavior, and since a class (in .Net) cannot inherit from more than one class (outside of an inheritance chain), the solution is to create an Interface.  Consider the following example:


Interface ISaveableControl
{
  void Save();
}



Then I could have a couple controls implement it:

class CustomTextBox : System.Windows.Forms.TextBox, ISaveableControl
{
  public CustomTextBox(string defaultValue)
  {
     base.Text = defaultValue;
  }

  public void Save()
  {
     ///Go to the database and update the associated record with the associated value
  }
}

class CustomComboBox : System.Windows.Forms.ComboBox, ISaveableControl
{
  public CustomTextBox(string defaultValue)
  {
     base.Items.Add(defaultValue);
     base.Text = defaultValue;
  }

  public void Save()
  {
     ///Go to the database and update the associated record with the associated value
  }
}


If I were to add the above controls to a basic System.Windows.Form, I could do something after a button was clicked (or some other event was triggered):


foreach(Control ctrl in this.Controls)
{
  if(ctrl is ISaveableControl)
  {
     ((ISaveableControl)ctrl).Save();
  }
}


And Voila, extending base controls to be more tightly coupled with your app.  There are decisions that need to be made to determine if this is a strategy your software should contain, because even though there is a lot of value in tightly coupled code (especially controls), there is also some value in keeping things loosely coupled.

No comments:

Followers

Search This Blog

Powered by Blogger.