Rizwan
Rizwan

Reputation: 119

How to implement observer pattern to work with user controls in asp.net

I've 2 user controls named UCCreateProfile.ascx (used for creating/editing profile data) and UCProfileList.ascx (used to display profile data in GridView). Now whenever a new profile created I want to update my UCProfileList control to show new entry.

The best solution against above problem I've to go for Observer Pattern. In my case UCCreatedProfile is a Subject/Observable and UCProfileList is a Observer and as per pattern definition when observer initialized it knows who is my Subject/Observable and add itself into Subject/Observable list. So whenever a change occurred in Subject/Observable it will be notified.

This pattern best fit my requirements but I'm getting few problems to implement this describe as follows.

I'm working under CMS (Umbraco) and I don't have any physical container page (.aspx). What I've to do is find UCCreateProfile (Subject/Observable) in UCProfileList (Observer) onLoad event using following code.

private Control FindCreateProfileControl()
{
     Control control = null;
     Control frm = GetFormInstance();
     control = GetControlRecursive(frm.Controls);

      return control;
}

where GetFormInstance() method is

private Control GetFormInstance()
    {
        Control ctrl = this.Parent;
        while (true)
        {
            ctrl = ctrl.Parent;
            if (ctrl is HtmlForm)
            {
                break;
            }
        }
        return ctrl;
    }

and GetControlRecursive() method is

 private Control GetControlRecursive(ControlCollection ctrls)
    {
        Control result = null;
        foreach (Control item in ctrls)
        {
            if (result != null) break;
            if (item is UCCreateProfile)
            {
                result = item;
                return result;
            }
            if (item.Controls != null)
                result = GetControlRecursive(item.Controls);
        }
        return result;
    }

this way I can find the UCCreateProfile (Subject/Observable) user control in UCProfileList (Observer) but the way to find out the (Subject/Observable) is not so fast. As you can see I need to loop through all controls and first find the HtmlForm control and then loop through all child controls under HtmlForm control and find the appropriate control we're looking for.

Secondly, placement of the user controls in container if very important my code will only work if UCCreatedProfile.ascx (Subject/Observable) placed before UCProfileList.ascx (Observer) because this way UCCreateProfile will load first and find in UCProfileList. But if someone changed the position of these 2 controls my code will not work.

So to get rid of these problems I need some solution which works faster and independent of the position of the controls.

I've figured out some solution as described below. Please do let me know if it is a good way of doing this. If there is an alternative, please let me know.

I've a session level variable (a dictionary with Dictionary<ISubject, List<Observer>>) . No matter which user control initialized/loaded first, User Control will add itself into this dictionary.
If Subject/Observable added first, the corresponding observers will be found in this dictionary.
If Observer added first it will added to the dictionary with a null entry. When the Subject added, the association is made.

Regards,

/Rizwan

Upvotes: 1

Views: 949

Answers (1)

Icarus
Icarus

Reputation: 63964

The Observer pattern is best implemented in .NET via events and delegates. If you use events and delegates, the Dictionary you mention becomes completely unnecessary. See for example this code below (only important pieces shown):

public partial class UserProfile : System.Web.UI.UserControl
{
    //This is the event handler for when a user is updated on the UserProfile Control
    public event EventHandler<UserUpdatedEventArgs> UserUpdated;

    protected void btnUpdate_Click(object sender, EventArgs e)
    {
        //Do whatever you need above and then see who's subscribed to this event
        var userUpdated = UserUpdated;
        if (userUpdated != null)
        {
            //Initialize UserUpdatedEventArgs as you want. You can, for example,
            //pass a "User" object if you have one
            userUpdated(this,new UserUpdatedEventArgs({....}));
        }
    }
}

public class UserUpdatedEventArgs : EventArgs
{
    public User UserUpdated {get;set;}
    public UserUpdatedEventArgs (User u)
    {
        UserUpdated=u;
    }
}

Now subscribing to the UserUpdated event from the UserProfile control on the UserListControl is as easy as this:

public partial class UserList : System.Web.UI.UserControl
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //Find the UserProfile control in the page. It seems that you already have a 
        //recursive function that finds it. I wouldn't do that but that's for another topic...
        UserProfile up = this.Parent.FindControl("UserProfile1") as UserProfile;
        if(up!=null)
           //Register for the event
           up.UserUpdated += new EventHandler<UserUpdatedEventArgs>(up_UserUpdated);
    }

    //This will be called automatically every time a user is updated on the UserProfile control
    protected void up_UserUpdated(object sender, UserUpdatedEventArgs e)
    {
        User u = e.UserUpdated;
        //Do something with u...
    }
}

Upvotes: 2

Related Questions