Contents
-
The Idea
-
The Control Library
-
IGroupingControl
-
GroupingEventArgs
-
GroupingManager
-
GroupingPanel
-
A picture of the library
-
The implementation
-
The Files
The Idea
If you would like to see the end result before reading on here it is: http://www.andrewrea.co.uk/groupenabledwebformcontrols/default.aspx
My idea for this sort of control library actually came from working with the LoginView control. There you can specify different controls to be shown dependant on:
- Anonymous
- Logged
- Role Groups
I found this very efficient, but it got me thinking. You will no doubt come across certain times where you would like certain controls to be disabled or enabled dependant on certain conditions with in your program, may be not show certain controls and only show others. My idea is to create a control set where by we have one main controlled object and child controls which subscribe to events from this controller.
It will also help with greatly reducing the amount of UI code required to hide and show controls. Another main concern while making these was this fact. "GROUPS" it may be the case that a control will be shown in one scenario but also in another, i.e. it belongs to more than one group. I liked this idea so i thought I will code it so you can have many groups assigned to one control.
Example: (Form controls in a questionnaire)
GROUP 1: Question modifications for C# Programmers
GROUP 2: Question modifications for C++ Programmers
GROUP 3: Question modifications for Java Programmers
GROUP 4: Question modifications for Java Programmers and C++ Programmers
GROUP 5: Question modifications for C# Programmers and C++ Programmers
GROUP 6: Question modifications for C# Programmers and Java Programmers
So you get the idea, there can be any number of controls and each control can have many groups, the control library I have done which is a simple extension of the Web Forms Control Library means I could make all GROUP 4 controls disabled with one line of code etc... and subsequently enable them.
The Control Library
As I say I have extended the web form default control library with grouping, the control library I have made consists of:
An Interface
IGroupingControl
/// <summary>
/// I have only put in three properties for the interface
/// </summary>
public interface IGroupingControl
{
string GroupNames { set; }
string GroupingManagerID { get; set; }
GroupingManager GroupingManagerControl { get; }
}
Event Arguments
There are only two at present but I feel that this could be extended much further using for example the Strategy Pattern.
GroupingEventArgs
/// <summary>
/// Contains the bare necesity of group name, and also a visible and enabled property
/// </summary>
public class GroupingEventArgs : EventArgs
{
private bool _isEnabled;
private bool _isVisible;
private string _groupName;
public bool IsEnabled
{
get
{
return _isEnabled;
}
set
{
_isEnabled = value;
}
}
public bool IsVisible
{
get
{
return _isVisible;
}
set
{
_isVisible = value;
}
}
public string GroupName
{
get
{
return _groupName;
}
set
{
_groupName = value;
}
}
public GroupingEventArgs(bool isEnabled, bool isVisible, string groupName)
{
_isEnabled = isEnabled;
_isVisible = isVisible;
_groupName = groupName;
}
}
A Control Class which should be supplied to the page at the top, it is a "GroupingManager" and is used to notify all Groupings controls on the page
The GroupingManager
public class GroupingManager : UserControl
{
public event EventHandler<GroupingEventArgs> Notified;
protected virtual void OnNotified(GroupingEventArgs e)
{
if (Notified != null)
Notified(this, e);
}
public void Disable(string groupName)
{
GroupingEventArgs e = new GroupingEventArgs(false, true, groupName);
e.GroupName = groupName;
OnNotified(e);
}
public void Enable(string groupName)
{
GroupingEventArgs e = new GroupingEventArgs(true, true, groupName);
e.GroupName = groupName;
OnNotified(e);
}
public void MakeVisible(string groupName)
{
GroupingEventArgs e = new GroupingEventArgs(true, true, groupName);
e.GroupName = groupName;
OnNotified(e);
}
public void MakeInvisible(string groupName)
{
GroupingEventArgs e = new GroupingEventArgs(true, false, groupName);
e.GroupName = groupName;
OnNotified(e);
}
private static bool FindPredicate(string currentValue, string toCompare)
{
if (currentValue == toCompare)
return true;
else
return false;
}
}
The above are the core ingredients to this control library, as I say the other controls are simply inheriting from the web from controls and extending them with the interface. I will paste in the code here for the GroupingPanel which will display how I achieve the functionality. NB: The code for the other objects is the same with the exception of changing the object name, constructor and also the base control it inherits from. I think this may be a case of where the C++ rule that you can inherit from multiple classes and interfaces would be useful here. Of course with C# you can only inherit from one object and multiple interfaces. I say this because I could simply use the same code in another object and inherit from the base control and also my object which provides extended functionality. Either way It uses an interface and here is one of the controls namely the GroupingPanel.
The GroupingPanel
/// <summary>
/// The grouping panel
/// </summary>
public class GroupingPanel : Panel,IGroupingControl
{
/// <summary>
/// The group names which belong to the controls
/// </summary>
private string[] _groupNames
{
get
{
return (string[])ViewState["GroupName"];
}
}
public GroupingPanel()
{
//
// TODO: Add constructor logic here
//
}
/// <summary>
/// Here I subscribe the the Grouping Manager Notified event
/// </summary>
/// <param name="e"></param>
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
GroupingManagerControl.Notified += new EventHandler<GroupingEventArgs>(GroupingManagerControl_Notified);
}
/// <summary>
/// This is where the magix happens
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
void GroupingManagerControl_Notified(object sender, GroupingEventArgs e)
{
System.Diagnostics.Debug.WriteLine("Entered");
if (Array.IndexOf(_groupNames,e.GroupName) >= 0)
{
this.Enabled = e.IsEnabled;
this.Visible = e.IsVisible;
}
}
#region ISubscriptionControl Members
/// <summary>
/// The string ID of the grouping manager
/// </summary>
public string GroupingManagerID
{
get
{
object o = ViewState["GroupingManagerID"];
if (o == null)
return String.Empty;
return ViewState["GroupingManagerID"].ToString();
}
set
{
ViewState["GroupingManagerID"] = value;
}
}
/// <summary>
/// This returns the grouping manager control
/// </summary>
public GroupingManager GroupingManagerControl
{
get
{
return (GroupingManager)Page.FindControl(GroupingManagerID);
}
}
/// <summary>
/// The reason why this is of type string and not string[]
/// is because it will trhow an error trying to assign to array
/// from the string representation in the mark up which is why
/// I provide a private accesor to the data above
/// </summary>
public string GroupNames
{
set
{
ViewState["GroupName"] = value.ToString().Split(',');
}
}
#endregion
}
A Picture of the library
The Implementation
As per the example URL at the start of this blog I created buttons on the left to trigger different calls to the Grouping Manager. e.g.
<asp:Button ID="Button5" runat="server" Text="Disable Group 1" OnClick="Button5_Click" />
With the code
protected void Button5_Click(object sender, EventArgs e)
{
groupingManager1.Disable("Group1");
}
So straight away this means that it would effect the following grouping controls:
<aebs:GroupingPanel ID="groupingPanel1" runat="server" GroupNames="Group1,Hybrid"
GroupingManagerID="groupingManager1">
<asp:Button ID="Button1" runat="server" Text="Button" />
</aebs:GroupingPanel>
<aebs:GroupingPanel ID="groupingPanel2" runat="server" GroupNames="Group1" GroupingManagerID="groupingManager1">
<asp:Button ID="Button2" runat="server" Text="Button" />
</aebs:GroupingPanel>
<aebs:GroupingPanel ID="groupingPanel3" runat="server" GroupNames="Group1,Hybrid"
GroupingManagerID="groupingManager1">
<asp:Button ID="Button3" runat="server" Text="Button" />
</aebs:GroupingPanel>
<aebs:GroupingPanel ID="groupingPanel4" runat="server" GroupNames="Group1" GroupingManagerID="groupingManager1">
<asp:Button ID="Button4" runat="server" Text="Button" />
</aebs:GroupingPanel>
Please notice that two of the grouping panels belong to both Group1 and also Hybrid. So this means that if I disable Group1 and then enable Hybrid, only the two controls with Hybrid in their group names will be enabled.
I hope that this library can be of some use to others and I know this could be extended way further to incorporate many more time saving / code saving ideas.
The Files
The library (http://www.andrewrea.co.uk/GroupEnabledWebFormControls/Grouping.rar)
The test site (http://www.andrewrea.co.uk/GroupEnabledWebFormControls/GroupEnabledWebFormControls.rar)
Example URL (http://www.andrewrea.co.uk/groupenabledwebformcontrols/default.aspx)