Saturday, May 22, 2010

Resetable Panel Asp.Net - Reset all values to default values of child controls and nested panels.

Well, there is no reset method for asp.net panel by the time of this article. But certainly we can implement a reset method by extending functionalities of required controls.
PS: If this functionality is widely use I would implement something like this. But it is only for less then 10 controls don't walk on this root.
As asp.net is extensible, we can extend Label, Textbox to have DefaultValues property and a mechanism to on and off (LoadDefaultValue which is true by default) the feature so that we can use it like ordinary controls.
  1. Implement's key feature is an interface called IXControl 
  2. Which has three members. Namely string DefaultValues { get; set; }, bool LoadDefault { get; set; } and void Reset();
  3. All X Controls implement this interface. 
  4. Inside the Reset method of each control, call common helper method called ResetProperties passing parameters, this control and DefaultValues property.
  5. DefaultValues propety should be a list of comma seperated { PropertyName=ProperyValue } pairs. Example DefaultValues="Text=DefaultText;ForeColor=Red;BackColor=Blue;Visible=false ... N
  6. Inside ResetProperties we decode DefaultValues string using string split and populate PropertyValue list
  7. Then use Reflection to go through each property of control and if propety name matchs one of in the list, set the value of the property using PropertyInfo
  8. Inside the panel Reset method, we call ResetInteranl so it will hock up all the child controls. Call Reset method using IXControl interface determining if the child type is IXControl.
  9. There is a catch, we need to go to children only if control is not a XPanel. Because once we call the Reset of XPanel it know how to reset all of it's children by itself
Extended controls and IXPanel interface : PS I have hosted custom controls in a separate assembly called Active.Web.UI.Controls. So you might nedd to change to namespace and assembly to get this working accroding to your control location.

Code:
/// <summary>
/// ControlManager and PropertyValue classes
/// </summary>
 
public class ControlManager
{
    public static void ResetProperties(Control control, string defaultValues)
    {
        if (string.IsNullOrEmpty(defaultValues)) return;
        List<PropertyValue> pvs = new List<PropertyValue>();
        foreach (string pv in defaultValues.Split(";".ToCharArray()))
        {
            string[] s = pv.Split("=".ToCharArray());
            if (s.Length == 2 && !string.IsNullOrEmpty(s[0]))
                pvs.Add(new PropertyValue() { Property = s[0].Trim(), Value = s[1] });
        }
        foreach (PropertyInfo p in control.GetType().GetProperties())
        {
            PropertyValue pv = pvs.Find(x => x.Property.Equals(p.Name));
            if (pv != null)
            {
                if (p.PropertyType.Equals(typeof(string)))
                    p.SetValue(control, pv.Value, null);
                else if (p.PropertyType.Equals(typeof(Color)))
                {
                    try { p.SetValue(control, new ColorConverter().ConvertFromString(pv.Value), null); }
                    catch { }
                }
                else if (p.PropertyType.Equals(typeof(bool)))
                {
                    bool value;
                    if (bool.TryParse(pv.Value, out value))
                        p.SetValue(control, value, null);
                }
                ///
                /// You can extend this for any other criteria
                ///
            }
        }
    }
}
public class PropertyValue
{
    public string Property { getset; }
    public string Value { getset; }
}
 
/// <summary>
/// IXControl interface
/// </summary>
 
public interface IXControl
{
    string DefaultValues { getset; }
    bool LoadDefault { getset; }
    void Reset();
}
 
/// <summary>
/// XLabel 
/// </summary>
 
public class XLabel : LabelIXControl
{
    public string DefaultValues { getset; }
    public bool LoadDefault { getset; }
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        if (this.LoadDefault && !this.Page.IsPostBack) this.Reset();
    }
    public void Reset()
    {
        ControlManager.ResetProperties(thisthis.DefaultValues);
    }
}
 
/// <summary>
/// XTextbox
/// </summary>
 
public class XTextBox : TextBoxIXControl
{
    public string DefaultValues { getset; }
    public bool LoadDefault { getset; }
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        if (this.LoadDefault && !this.Page.IsPostBack) this.Reset();
    }
    public void Reset()
    {
        ControlManager.ResetProperties(thisthis.DefaultValues);
    }
}
 
/// <summary>
/// XPanel
/// </summary>
 
public class XPanel : PanelIXControl
{
    public string DefaultValues { getset; }
    public bool LoadDefault { getset; }
    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);
        if (this.LoadDefault && !this.Page.IsPostBack) this.Reset();
    }
    public void Reset()
    {
        ControlManager.ResetProperties(thisthis.DefaultValues);
        this.ResetInternal(this.Controls);
    }
    private void ResetInternal(ControlCollection controlCollection)
    {
        foreach(Control control in controlCollection)
        {
            if (control is IXControl) ((IXControl)control).Reset();
            if (control.Controls.Count > 0 && !control.GetType().Equals(typeof(XPanel)))
                this.ResetInternal(control.Controls);
        }
    }
}

Markup:

<%@ Page Language="C#" AutoEventWireup="true" %>
<%@ Register Assembly="Active.Web.UI.Controls" Namespace="Active.Web.UI.Controls" TagPrefix="active" %>
<%@ Import Namespace="System.Drawing" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head2" runat="server">
    <title>Reset Panel</title>
    <script runat="server">
        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);
            for (int i = 0; i < 30; i++)
            {
                this.xpnlContainer.Controls.Add(
                    new XLabel() { DefaultValues = String.Format("Text={0};Visible=true;ForeColor=Red""Label " + i) });
                this.xpnlContainer.Controls.Add(
                    new XTextBox() { DefaultValues = String.Format("Text={0};Visible=true;BackColor=Blue""Textbox " + i) });
                XPanel panel =new XPanel() { BackColor = System.Drawing.Color.Red, Visible = false, DefaultValues = "Visible=true" };
                panel.Controls.Add(new XLabel() { Text = "Nested Label - Init", DefaultValues = "Text=Nested Label Default" });
                this.xpnlContainer.Controls.Add(panel);
            }
        }
        public void Reset(object sender, EventArgs e)
        {
            this.xpnlContainer.Reset();
        }        
    </script>
</head>
<body>
    <form id="form2" runat="server">
    <div>
        <active:XPanel runat="server" ID="xpnlContainer" />
        <asp:Button runat="server" ID="btnReset" Text="Reset" OnClick="Reset" />
        <asp:Button runat="server" ID="btnPostback" Text="Postback" />
    </div>
    </form>
</body>
</html>

No comments:

Azure Storage Account Types

Defferent Types of Blobs Block blobs store text and binary data. Block blobs are made up of blocks of data that can be managed individually...