This post will cover the ControlLoader. This custom control extends the PlaceHolder to prove some more intelligence around loading a control. One of the primary concerns when using dynamically loaded controls is trying to work peacefully with the natural page lifecycle. The first snag often hit is that on Postback if a control want's to participate in the ViewState rehydration and normal Control Eventing, it needs to be added to the control tree at OnInit. This is usually not too much of an issue, unless you need information from the post to tell you which control to load. If you do, you have to leave the safe grounds of the ASP.Net page lifecycle and work with the request direction. The ControlLoaderManager/ControlLoader wrap up the functionality, and use a public event to delegate the work of selecting a control path based upon a control target
Below is the full code listing but here are a few key sections:
public event GetControlPathHandler GetControlPath;
private string getControlPath()
{
if (null != GetControlPath)
{
return GetControlPath(this, new GetControlPathEventArgs(_targetControlKey));
}
return null;
}
This event and private method are what delegate the work of turning a control target into a control path. It allows the implementing store to provide the appropriate selection logic.
protected override void OnInit(EventArgs e)
{
ControlLoaderManager.RegisterControlLoader(Page, this);
string path = getControlPath();
if (!string.IsNullOrEmpty(path))
{
_loadedControl = Page.LoadControl(path);
_loadedControl.ID = this.ID + CTLIDEXT;
this.Controls.Add(_loadedControl);
}
base.OnInit(e);
}
protected override void OnPreRender(EventArgs e)
{
if (_changed || _loadedControl == null)
{
if (null != _loadedControl)
{
this.Controls.Remove(_loadedControl);
}
string path = getControlPath();
if (!string.IsNullOrEmpty(path))
{
_loadedControl = Page.LoadControl(path);
_loadedControl.ID = this.ID + CTLIDEXT;
this.Controls.Add(_loadedControl);
}
}
base.OnPreRender(e);
}
These event handlers do the work of loading the dynamic control. Loading can occur in OnInit, so any previously loaded Controls can participate in the natural page cycle, and in OnPreRender so an Event like the OnClick of a LinkButton can set the target of the ControlLoader without any special logic.
The Full listing:
public class GetControlPathEventArgs : EventArgs
{
public string Target
{
get { return _target; }
}
public GetControlPathEventArgs(string target)
{
_target = target;
}
private string _target;
}
public delegate string GetControlPathHandler(object sender, GetControlPathEventArgs e);
[DefaultEvent("GetControlPathHandler")]
[ToolboxData("<{0}:ControlLoader runat=server></{0}:ControlLoader>")]
public class ControlLoader : PlaceHolder
{
public event GetControlPathHandler GetControlPath;
public string TargetControlKey
{
get { return _targetControlKey; }
set {
if (null != _targetControlKey && value != _targetControlKey)
{
_changed = true;
}
_targetControlKey = value; }
}
public string Key
{
get { return _key; }
set { _key = value; }
}
protected override void OnInit(EventArgs e)
{
ControlLoaderManager.RegisterControlLoader(Page, this);
string path = getControlPath();
if (!string.IsNullOrEmpty(path))
{
_loadedControl = Page.LoadControl(path);
_loadedControl.ID = this.ID + CTLIDEXT;
this.Controls.Add(_loadedControl);
}
base.OnInit(e);
}
protected override void OnPreRender(EventArgs e)
{
if (_changed || _loadedControl == null)
{
if (null != _loadedControl)
{
this.Controls.Remove(_loadedControl);
}
string path = getControlPath();
if (!string.IsNullOrEmpty(path))
{
_loadedControl = Page.LoadControl(path);
_loadedControl.ID = this.ID + CTLIDEXT;
this.Controls.Add(_loadedControl);
}
}
base.OnPreRender(e);
}
#region private helper methods
private string getControlPath()
{
if (null != GetControlPath)
{
return GetControlPath(this, new GetControlPathEventArgs(_targetControlKey));
}
return null;
}
#endregion private helper methods
private string _targetControlKey;
private string _key;
private bool _changed = false;
private Control _loadedControl;
private static readonly string CTLIDEXT = "DynCtl";
}
Print | posted on Sunday, October 07, 2007 9:16 PM