ASP.NET 2.0 Fun Coding #1

Well I named it Fun Coding as I really have no idea what to call it? J

Here is the scenario.

*If you know a better way, let me know.

The project hierarchy:

MasterPage

è Default.aspx

o   uclProgramManagement.ascx

§  MultiView

·         View1

o   uclLogicstics.ascx

o   uclBanking.ascx

·         View2

o   uclInsurance.ascx

Nothing special right J

Assuming each child control (uclLogistics.ascx, uclBanking.ascx and uclInsurance.ascx) has html controls like below:

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="uclBanking.ascx.cs"

    Inherits="uclBanking" %>

<table id="tblMain" summary="This table holds all necessary tables and user controls"

    class="tableGeneral">

    <tr>

        <th>

            <asp:Label ID="lblBankingHeader" runat="server" Text="Banking Information" />

        </th>

    </tr>

    <tr>

        <td>

            <br />

        </td>

    </tr>

    <tr>

        <td>

            <asp:GridView ID="grvBanking" runat="server" SkinID="GeneralView" DataKeyNames="BankingID" AutoGenerateColumns="False">

                <Columns>                   

                    <asp:BoundField DataField="BankingType" HeaderText="Type" SortExpression="BankingType" />

                </Columns>

            </asp:GridView>

        </td>

    </tr>

    <tr>

        <td>

            <br />

        </td>

    </tr>

    <tr>

        <td class="tableRowForButtons">

            <asp:Button ID="btnAddRecord" runat="server" Text="Add Record" SkinID="AddRecordButton"

                OnClick="btnAddRecord_Click" />

        </td>

    </tr>

    <tr>

        <td>

            <br />

        </td>

    </tr>

    <tr>

        <td>

            <table id="tblPanel" class="tableStyle">

                <tr>

                    <td>

                        <asp:Panel ID="pnlInput" runat="server" SkinID="PanelView">

                            <table id="tblInput" class="tableGeneral">

                                <tr>

                                    <td class="tableColumn1">

                                    </td>

                                    <td class="tableColumn2">

                                    </td>

                                    <td class="tableColumn3">

                                    </td>

                                </tr>                               

                                <tr>

                                    <td>

                                        Banking Type <em>is</em>

                                    </td>

                                    <td>

                                        :

                                    </td>

                                    <td>

                                        <asp:DropDownList ID="ddlBankingType" runat="server" AutoPostBack="True" />

                                        <asp:RequiredFieldValidator ID="rfvBanking" runat="server" ErrorMessage="Banking Type is required"

                                            ControlToValidate="ddlBankingType" Display="Dynamic" />

                                    </td>

                                </tr>

                            </table>

                        </asp:Panel>

                    </td>

                </tr>

                <tr>

                    <td>

                        <br />

                    </td>

                </tr>

                <tr>

                    <td class="tableRowForButtons">

                        <asp:Button ID="btnSave" runat="server" Text="Save" SkinID="GenericButton" OnClick="btnSave_Click" />

                        <asp:Button ID="btnReset" CausesValidation="false" runat="server" Text="Reset" SkinID="GenericButton" OnClick="btnReset_Click" />

                        <asp:Button ID="btnClose" CausesValidation="false" runat="server" Text="Close" SkinID="GenericButton" OnClick="btnClose_Click" />

                    </td>

                </tr>

            </table>

        </td>

    </tr>

</table>

Okay from the code above you will notice that I have a panel “pnlInput” which contains the necessary controls to insert new record into the GridView.

Now, visualize this. You will have these 3 user controls in the same web form. Check out the page hierarchy. Taking uclBanking an example. When you click on AddRecord, it will display the “pnlInput” so that you can insert a new record. When you press close, it will hide this “pnlInput”. Same to the other 2 user controls.

So what is the problem here? What if you click AddRecord on all 3 user controls, what will you see?

Definitely all the 3 user control “pnlInput” will be visible. It is nothing wrong about this. Now your customer gives you a call and tells you that when he clicks on the 1st user control’s AddRecords, he expects to see this:

a.       uclBanking “pnlInput” Visible=”True”

b.      uclLogistics “pnlInput” Visible=”False”

c.       uclInsurance “pnlInput” Visible=”False”

This applies to the other user controls.

There are quite a number of ways, but how to maintain less intact among user controls. You can of course do this way:

a.       user control A notifies to user control B to close panel

b.      user control A notifies to user control C to close panel

Looks pretty okay. What if you have 15 user controls? User control A has to speak directly to other 14 user controls. That is a total madness.

So what is a better way?

In my honest opinion, I will do this instead:

Since I have 15 user controls, I will create a parent and child relationships. 1 parent and 15 children.

This parent will act as the publisher and the other 15 will subscribe to this parent.

Let’s get started.

1.       Create a new interface “IPublisher” in App_Code

public interface IPublisher

{

    void Attach(ISubscriber subscriber);

    void Detach(ISubscriber subscriber);

}

2.       Visualize Attach as Adding a new child to the parent. Detach will be the opposite.

3.       Now you need another new interface “ISubscriber” in App_Code

 

public interface ISubscriber

{

    void Update(bool isVisible);

}

 

4.       Now ask yourself why you need an Update method here? For my case each user control needs to have this Update method so you can do necessary callings here. I will actually hide the panel here.

5.       Next, create a new class “ControlCentre” in AppCode. This class will implement IPublisher.

 

using System;

using System.Collections.Generic;

 

public sealed class ControlCentre : IPublisher

{

    List<ISubscriber> subscribers = new List<ISubscriber>();

 

    /// <summary>

    /// Notifies all the subscribers

    /// </summary>

    /// <param name="isVisible"></param>

    public void Notify(bool isVisible)

    {

        // Loop into all the subscribers or user controls

        foreach (ISubscriber subscriber in subscribers)

        {

            subscriber.Update(isVisible);

        }

    }

 

    #region IPublisher Members

 

    /// <summary>

    /// Add to the list of subscribers

    /// </summary>

    /// <param name="subscriber"></param>

    public void Attach(ISubscriber subscriber)

    {

        subscribers.Add(subscriber);

    }

 

    /// <summary>

    /// Remove from list of subscribers

    /// </summary>

    /// <param name="subscriber"></param>

    public void Detach(ISubscriber subscriber)

    {

        subscribers.Remove(subscriber);

    }

 

    #endregion

}

 

6.       Looks straightforward. The thing to take note is the Notify method. Basically assuming you have 15 subscribers, it will loop into all the 15 subscribers and updates all of them.

7.       You need create one last interface “ICallingCentre” in your App_Code.

 

public interface IControlCentre

{

    void NotifyAll(bool isVisible);

}

 

8.       For this interface, you will see the usage later.

9.       Where do you attach these user controls? The page (.aspx) or the parent container (.ascx). The answer is the parent container.

10.   Why? The answer is pretty obvious. Basically you add the 3 user controls into the parent container (.ascx) instead of the page. So this parent container consists the instances of the user controls.

11.   Add this code into your uclProgramManagement.asc

 

public partial class uclProgramManagement: System.Web.UI.UserControl, IControlCentre

{

 

}

 

12.   Make sure it implements IControlCentre interface. Then you need to implement the method in that interface.

 

#region IControlCentre Members

 

public void NotifyAll(bool isVisible)

{

    _dataSource.Notify(isVisible);

}

 

#endregion

 

13.   You need to attach the subscribers in the Page_Load event.

 

private ControlCentre _dataSource;

                

protected void Page_Load(object sender, EventArgs e)

{

    if (!Page.IsPostBack)

    {

       // your code here

    }

 

    _dataSource = new ControlCentre();

    _dataSource.Attach(uclBanking);

    _dataSource.Attach(uclInsurance);

    _dataSource.Attach(uclLogicstics);          

}

 

14.   At this moment I only have 3 user controls. If you have more user controls, just add into the list.

15.   Next, all your user controls need to implement the ISubscriber interface.

 

public partial class uclBanking : System.Web.UI.UserControl, ISubscriber

{ }

 

16.   Then implements the method of the interface

 

#region ISubscriber Members

 

public void Update(bool isVisible)

{

    SetPanelVisibility(isVisible);

}

 

#endregion

 

17.   Now if you click on AddRecord button, you expect it to notify the parent to close all the user controls first before proceeding with other process.

18.   Add this code below for the AddRecord button event.

 

protected void btnAddRecord_Click(object sender, EventArgs e)

{      

    ((IControlCentre)Parent.Parent.Parent).NotifyAll(false);

 

    SetPanelVisibility(true);

}

 

private void SetPanelVisibility(bool isVisible)

{

    pnlInput.Visible = isVisible;

}

 

19.   You will notice that I utilize the IControlCentre to cast the Parent control so I can access the NotifyAll method instead of creating unnecessary instances.

20.   You will be also surprised why I use Parent.Parent.Parent instead of just Parent? I will elaborate as below.

Parent – View

Parent.Parent – MultiView

Parent.Parent.Parent – User Control

21.   So now you know why I choose to do that?

22.   Okay repeat steps 15 – 20 for the other user controls. Give it a try J

Nevertheless every technique has a pro and con.

Pros:

a.       Codes are cleaner and remove dependencies between user controls. Only rely on the ControlCentre to manage this relationship through the usage of IControlCentre.

Cons:

a.       Basically it will close all the panels including the calling User Control

I know this might be basic for a lot of people. But hope someone find this interesting. Do let me know if there is a better way so probably I can improve this. I am in the middle of researching on closing all panels except the calling user control J.

Published Thursday, February 22, 2007 11:11 PM by chuawenching
Filed under: ,