Smarter HybridControl Collections in Gaia Ajax 3.5

by Jan Blomquist 15. February 2009 21:30

 

When building reusable server controls we have a plethora of different ways to build them. There are pros and cons to every solution and finding the best approach is not always easy. In Gaia Ajax 3.0 we introduced the HybridControl which is a combination of a composite control and a container control. That means we add some of our own controls and aspects to the control in addition to the controls the developer adds. Since we haven't seen this pattern (please correct us if we are wrong) we named the pattern HybridComposition.

Some examples of HybridControls include

  • Window
  • ExtendedPanel
  • TreeView
  • Toolbar 

The immediate benefit of the HybridControl is that you can directly add child controls in design time, markup and runtime. In runtime you get simple access to the controls just by typing in their name or accessing them through the controls collection.

   1:  Window1.Controls.Add(new LiteralControl("Hello Gaia Developers")); 

Issues

There were however some issues we encountered with this approach. Here are just some of the problems and you probably encountered one or more of them.

  1. The Controls collection wasn't fully yours anymore. It was mixed, partially ours, partially yours. That means a Controls.Clear() would destroy the HybridControl because the composite controls would be removed aswell.
  2. ForceAnUpdate implementation would get in the way of property serialization. That means when you tried to re-render for example the Window, the Caption would be left untouched even if you changed it, because partial rendering would overrule serialization.
  3. In some controls like the TreeView where you want to access both TreeViewItems and your custom controls, there were no clear separation of what belonged where. Effectively you ended up searching the Controls collection and filtering out stuff manually.

Solution

We've created specialized Control Collections and Collection wrappers in Gaia Ajax 3.5 to offer a clean and intuitive solution to the above problems. Since we cannot touch the Controls collection itself because ASP.NET heavily relies on it, we have chosen an approach were we sit on top of the existing collection and offer specalized behaviour on a pr/hybridcontrol basis. This generic wrapper is the foundation for all the other collections.

   1:  public abstract class ControlCollectionWrapper<T> : ICollection<T> where T : Control {}
The most important function that sits here is the IsValidControl(). For each control in the collection, derived collections can implemented this function to verify if the current control is valid in the collectionwrapper or not.
   1:  protected abstract bool IsValidControl(Control control);
For example in HybridPanelBase, the ancestor of Window we use the HybridControlCollection which is implemented like this
   1:  public class HybridControlCollection<T> : ControlCollectionWrapper<T> where T : Control
   2:  {
   3:      private readonly ICollection<Control> _skipTheseControls;
   4:      
   5:      public HybridControlCollection(T ownerControl, ICollection<Control> skipTheseControls) 
   6:      : base(ownerControl)
   7:      {
   8:          _skipTheseControls = skipTheseControls;
   9:      }
  10:   
  11:      protected override bool IsValidControl(Control control)
  12:      {
  13:          return !_skipTheseControls.Contains(control);
  14:      }
  15:  }

Based on the ControlCollectionWrapper we've currently created the following derived collections.

  • ControlCollectionExcept
  • ControlCollectionOf
  • HybridControlCollection

On the Window we define two collections, one is for the composition controls and the other is for the normal childcontrols. The signatures are as follows

   1:  protected internal ICollection<Control> CompositionControls {get;}
   2:  public virtual HybridControlCollection<Control> ChildControls {get;}

Usage

With this approach you will always have access to all your custom childcontrols in the ChildControls collection wrapper. The following operations which was considered hazardious in the 3.0 release is now safe and correct.

   1:  Window.ChildControls.Clear();
   2:  Window.ChildControls.InsertAt(0, new Control()); 
   3:  Window.ChildControls.RemoveAt(0);
Let's move over to the TreeView. The TreeView contains TreeViewItems which can be made up of more TreeViewItems or custom controls. Here we use both the ControlCollectionOf and ControlCollectionExcept to offer ways to manipulate both the Child TreeViewItems and custom ChildControls. The collections are implemented as follows
   1:  public ControlCollectionOf<TreeViewItem> TreeViewItems { get;}
   2:  public ControlCollectionExcept<TreeViewItem> ChildControls { get;}

It basically means the first collection is made of TreeViewItems, whereas the other collection is made up of anything, but TreeViewItems. Because we now have these collections on the TreeView, we suddenly have the same flexibility on the TreeView if we want to

  • Modify the TreeViewItems collection and perform now supported operations like Clear(), InsertAt(), RemoveAt(), etc.
  • Add custom ChildControls without having to deal with the TreeViewItems which are also in the collection.
  • It greatly simplifies ForceUpdate() scenarios since you have greater control over what you want to have re-rendered and not. We also have a few more control collections in Gaia Ajax 3.5, including the GenericControlCollection and AspectCollection.
We really hope you appreciate the research and development we are doing in this HybridControl space and we'd love to have your feedback on it. Dino Esposito reacted by saying "Wow! This is much better". We hope you think the same. 

Tags: , ,

Ajax | Gaia

Comments

2/16/2009 2:39:31 PM #

Trackback from DotNetShoutout

Smarter Control Collections for HybridControls in Gaia Ajax 3.5 (C#)

DotNetShoutout

Comments are closed