开发者

Observers in ASP.Net with Delegates

Well, i'm working in a asp.net 3.5 site.

I have set an Observer like this:

public delegate void ActionNotification();

protected Dictionary<string, List<ActionNotification>> Observers
{
    get
    {
        Dictionary<string, List<ActionNotification>> _observers = Session["Observers"] as Dictionary<string, List<ActionNotification>>;
        if (_observers == null)
        {
            _observers = new Dictionary<string, List<ActionNotification>>();
            Observers = _observers;
        }
        return _observers;
    }
    set
    {
        Session["Observers"] = value;
    }
}

public void Attach(string actionName, ActionNotification observer)
{
    if (!Observers.ContainsKey(actionName))
    {
        Observers.Add(actionName, new List<ActionNotification>());
    }
    Observers[actionName].Add(observer);
}

public void Detach(string actionName, ActionNotification observer)
{
    if (Observers.ContainsKey(actionName))
    {
        Observers[actionName].Remove(observer);
    }

}
public void DetachAll(string actionName)
{
    if (Observers.ContainsKey(actionName))
    {
        Observers.Remove(actionName);
    }
}

public void Notify(string action)
{
    if (Observers.ContainsKey(action))
    {
        foreach (ActionNotification o in Observers[action])
        {
开发者_StackOverflow社区            o.Invoke();
        }
    }
}

I use the observer like this:

//Esta es llamada al notify con cierto action       
protected void btnNext_Click(object sender, ImageClickEventArgs e)          
{           
    Notify("Next");         
} 
//Y este es el register del Listener            
Attach("Next", new ActionNotification(NextButton_Click)); 

If before the o.Invoke(); for example i change the page title to "Hello". And inside the "NextButton_Click" I set it to "Goodbye", after the NextButton_Click finish, the Title goes back to "Hello"...

Any idea why?


I think problem is that the "Page" in your NextButton_Click event is not the same page as the page you set the title to "Hello" on. Because you are passing around events in the session when the event is raised the object is acts on is no longer in scope. You can recreate it with the following code (which is using EventHandlers, but they are basically the same as what you have outlined in your code)

protected void Page_Load(object sender, EventArgs e)
{
    this.Page.Title = "test";

    //Store it in your session...seems like a weird thing to do given how your page should be stateless, so I would think about what you are
    //trying to do a bit more carefully.  You don't want to call an event handler such as test below from another page in your asp.net app.
    Dictionary<string, EventHandler> myEvents = null;
    if (Session["Invokers"] == null)
    {
        myEvents = new Dictionary<string, EventHandler>();
        Session["Invokers"] = myEvents;
    }
    else
    {
        myEvents = Session["Invokers"] as Dictionary<string, EventHandler>;
    }
    //If the event handler key is not in there then add it
    if (myEvents.ContainsKey("buttonClickOnPageDefault") == false)
    {
        //Subscribe to event (i.e. add your method to the invokation list
        this.TestEvent += new EventHandler(test);
        myEvents.Add("buttonClickOnPageDefault", this.TestEvent);
    }
    else
    {
        //if it does contain this key then you may already be subscribed to event, so unsubscribe in case and then resubscribe...you could
        //probably do this more elegantly by looking at the vales in the GetInvokationList method on the eventHandler
        //Wire up the event
        this.TestEvent -= new EventHandler(test);
        this.TestEvent += new EventHandler(test);
    }
    //Resave the dictionary.
    Session["Invokers"] = myEvents;
}

void test(object o, EventArgs e)
{
    this.Page.Title = "testEvent";
}

public event EventHandler TestEvent;

protected void Button1_Click(object sender, EventArgs e)
{
    if (Session["Invokers"] != null)
    {
        Dictionary<string, EventHandler> myEvents = (Dictionary<string, EventHandler>)Session["Invokers"];
        if (myEvents.ContainsKey("buttonClickOnPageDefault"))
        {
            EventHandler ev = myEvents["buttonClickOnPageDefault"];
            ev(null, EventArgs.Empty);
        }
    }
}

If you put the above code in an asp.net page it will never change page title, but if you put a breakpoint in the Test method you will see it being hit. The reason is that its being hit in a different page (and that page is out of scope and may not be garbage collected as your event still has a reference to it, so this could cause a memory leak...be careful with it!). Really you probably shouldn't be using your events this way (at least not to act on a page...maybe it has some utility for domain objects). Note that the following will work (as its acting on the same page)

protected void Page_Load(object sender, EventArgs e)
{
    this.Page.Title = "test";

    //Store it in your session...seems like a weird thing to do given how your page should be stateless, so I would think about what you are
    //trying to do a bit more carefully.  You don't want to call an event handler such as test below from another page in your asp.net app.
    this.TestEvent += new EventHandler(test);
    Session["Invoker"] = this.TestEvent;
}

void test(object o, EventArgs e)
{
    this.Page.Title = "testEvent";
}

public event EventHandler TestEvent;

protected void Button1_Click(object sender, EventArgs e)
{
    if (Session["Invoker"] != null)
    {
        EventHandler ev = (EventHandler)Session["Invoker"];
        ev(null, EventArgs.Empty);
    }
}

Hope that gives you some pointers to where your problem might be.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜