Solved

Event Delegates - Raising event fails on web control.

Posted on 2008-10-28
17
1,022 Views
Last Modified: 2013-11-07
I thought this should be a simple, clean way of accomplishing a simple requirement to display multiple menus using a single web form:

1. Create an ASP.NET web app.
2. Make a placeholder in an update panel on the default.aspx page.
3. Add to the project two web controls. Place a couple buttons on each.
4. In each web control's code behind, create a delegate - event pattern for communicating information back to the default.aspx code behind.
5. In the default.aspx code behind, wire-up a local method as the handler for each web control's event.
6. When the default.aspx fires it's page init, you load up the first web control into the placeholder.
7. User clicks a button in the loaded (and rendered) first web control that supposedly fires an event (subscribed to in default.aspx) wherein it defines a second web control to put in the placemarker.

It works right up till the point where I click on a "main menu" button in the first control. When the button click event fires, I raise an event to tell default.aspx.cs to load up a different web control, only the event itself won't fire because it's null. It's probably simpler just to show me the right way than for me to drag parts of my code out.
0
Comment
Question by:Reddgum
  • 8
  • 8
17 Comments
 
LVL 13

Expert Comment

by:numberkruncher
ID: 22826303
If you are simply daisy-chaining events you can use the following:
public event EventHandler Button1Click

{

    add { button1.Click += value; }

    remove { button1.Click -= value; }

}

Open in new window

0
 
LVL 3

Author Comment

by:Reddgum
ID: 22826436
Hi Numberkruncher,

I'm not sure you understand - or I'm not understanding how your code snippet answers the stated problem.

Ultimately, the idea is to provide a simple interface for a user to navigate through 5 or perhaps 6 menus. I do NOT want all of the menu options to display at the same time. Coupled with this requirement is levels of access control. Some users will see all of the buttons, others may only see one or two.

In attempting to solve the requirement, another developer suggested that I dynamically load web controls. Each web control has the discrete elements that encapsulate the menu for a specific function - and in my example, I have a reset password feature and an edit user feature. Some users will see both buttons, some will only see the reset password.

Once the user is done on that web control, they may want to do something else in another section of the menu - so I provide a Main Menu button. When that button is clicked, I wish to load the Main Menu web control into the placeholder of the default.aspx form, and have the user see and navigate through those options.

Hopefully this is a clearer explanation.


0
 
LVL 20

Expert Comment

by:Juan_Barrera
ID: 22826585
Hi,

Without having a look at your code, it would be a bit difficult to be more specific, but I would like to pinpoint a few common issues that may be related with your problem:

If adding controls dynamically:

- Recreate them on every postback, by overriding CreateChildControls, not on Page.Init
- Assign a fixed ID to them. In this way, upon postback, ASP.NET properly recognises them.
- Set the ID After the control has been added to the controls tree.
- Same with the event handlers.

I hope this helps,



0
 
LVL 13

Expert Comment

by:numberkruncher
ID: 22826666
If you store your interface in XML format then you could generate the interface from the selected menu node.

With an XML like the following, if "Section A" is clicked, you could render items 1 to 3, if "Section B" is clicked, you could render items 4 to 5.

To restrict access permissions you can use:

if (String.IsNullOrEmpty(itemRole) || HttpContext.Current.User.IsInRole(itemRole))
{
     // Render item within page.
}

If this is the way you want to go I can provide more information.
<?xml version="1.0" ?>

<menus>

   <menu label="Section A">

      <item label="Item 1" url="Page1.aspx" />

      <item label="Item 2" url="Page2.aspx" />

      <item label="Item 3" url="Page3.aspx" role="Administrators" />

   </menu>

   <menu label="Section B">

      <item label="Item 4" url="Page4.aspx" />

      <item label="Item 5" url="Page5.aspx" />

      <item label="Item 6" url="Page6.aspx" />

   </menu>

</menus>

Open in new window

0
 
LVL 3

Author Comment

by:Reddgum
ID: 22826820
Numberkruncher:
That looks like it'll work for what I'm doing. What's the setup?
0
 
LVL 13

Expert Comment

by:numberkruncher
ID: 22827084
Sorry for the delay...

I have attached a sample project for you. I have added this menu functionality into a user control. I will leave the presentation to you, at the moment the menu is rendered vertically, where items are next to each other.

All top-level menu nodes are visible, and when you select another menu, it becomes visible.
0
 
LVL 13

Accepted Solution

by:
numberkruncher earned 500 total points
ID: 22827123
EE wont let met attach the files. I will have to post the source for each file individually. Sorry about this.
menus.xml

========================================================

<?xml version="1.0"?>

<menus>

   <menu label="Section A">

      <item label="Item 1" url="Page1.aspx" />

      <item label="Item 2" url="Page2.aspx" />

      <item label="Item 3" url="Page3.aspx" role="Administrators" />

   </menu>

   <menu label="Section B">

      <!-- Supports virtual paths. -->

      <item label="Item 4" url="~/Page4.aspx" />

      <item label="Item 5" url="~/Page5.aspx" />

      <item label="Item 6" url="~/Page6.aspx" />

   </menu>

</menus>
 
 
 
 

MenusControl.ascx

========================================================

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="MenusControl.ascx.cs" Inherits="MenusControl" %>
 
 
 
 

MenusControl.ascx.cs

========================================================

using System;

using System.Collections;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;

using System.Xml.XPath;
 

public partial class MenusControl : System.Web.UI.UserControl, IPostBackEventHandler

{

    #region IPostBackEventHandler Members
 

    public void RaisePostBackEvent(string eventArgument)

    {

        if (!String.IsNullOrEmpty(eventArgument))

            SelectedLabel = eventArgument;

    }
 

    #endregion
 

    #region Event Handlers
 

    protected void Page_Load(object sender, EventArgs e)

    {
 

    }
 

    #endregion
 

    #region Overrides
 

    protected override void OnPreRender(EventArgs e)

    {

        Page.RegisterRequiresRaiseEvent(this);
 

        XPathDocument document = new XPathDocument(Server.MapPath("~/menus.xml"));

        CreateOuterMenuItems(document.CreateNavigator());
 

        base.OnPreRender(e);

    }
 

    #endregion
 

    #region Methods
 

    private void AddLiteral(string text)

    {

        Literal newLiteral = new Literal();

        newLiteral.Text = text;

        Controls.Add(newLiteral);

    }
 

    private void CreateOuterMenuItems(XPathNavigator node)

    {

        XPathNodeIterator it = node.Select("/menus/menu");

        while (it.MoveNext())

        {

            XPathNavigator activeNode = it.Current;

            string itemLabel = activeNode.GetAttribute("label", string.Empty);
 

            // Render outer menu item.

            HyperLink linkItem = new HyperLink();

            linkItem.Text = itemLabel;

            linkItem.NavigateUrl = Page.ClientScript.GetPostBackClientHyperlink(this, itemLabel);

            linkItem.Font.Bold = true;

            linkItem.Font.Size = FontUnit.XLarge;

            Controls.Add(linkItem);
 

            AddLiteral("<br />");
 

            // Render inner menu items?

            if (itemLabel == SelectedLabel)

                CreateInnerMenuItems(activeNode);

        }

    }
 

    private void CreateInnerMenuItems(XPathNavigator node)

    {

        // Get selected menu from navigator.

        XPathNodeIterator it = node.Select("item");

        while (it.MoveNext())

        {

            XPathNavigator activeNode = it.Current;
 

            string itemRole = activeNode.GetAttribute("role", String.Empty);

            if (String.IsNullOrEmpty(itemRole) || Context.User.IsInRole(itemRole))

            {

                // Render inner menu item.

                HyperLink linkItem = new HyperLink();

                linkItem.Text = activeNode.GetAttribute("label", String.Empty);

                linkItem.NavigateUrl = Page.ResolveClientUrl(activeNode.GetAttribute("url", String.Empty));

                Controls.Add(linkItem);
 

                AddLiteral("<br />");

            }

        }

    }
 

    #endregion
 

    #region Properties
 

    public string SelectedLabel

    {

        get

        {

            return ViewState["SelectedLabel"] as string ?? "Section A";

        }

        set

        {

            ViewState["SelectedLabel"] = value;

        }

    }
 

    #endregion

}
 
 
 
 

Default.aspx

========================================================

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
 

<%@ Register src="MenusControl.ascx" tagname="MenusControl" tagprefix="uc1" %>
 

<!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 runat="server">

    <title>Untitled Page</title>

</head>

<body>

    <form id="form1" runat="server">

    <div>

        <uc1:MenusControl ID="MenusControl1" runat="server" />

    </div>

    </form>

</body>

</html>
 
 
 
 

Default.aspx.cs

========================================================

using System;

using System.Configuration;

using System.Data;

using System.Linq;

using System.Web;

using System.Web.Security;

using System.Web.UI;

using System.Web.UI.HtmlControls;

using System.Web.UI.WebControls;

using System.Web.UI.WebControls.WebParts;

using System.Xml.Linq;
 

public partial class _Default : System.Web.UI.Page 

{

    protected void Page_Load(object sender, EventArgs e)

    {
 

    }

}

Open in new window

0
 
LVL 3

Author Comment

by:Reddgum
ID: 22831964
Ok,

Got all the code to compile finally - apparently, Visual studio 2008 doesn't like you overriding their partial classes - I have to manually re-add the inheritances to each class or it'll bomb each time I compile and run.

And when it runs. I get nothing. Nothing displays. I put a breakpoint in every possible location with code, and none of them are hit. Is there a missing event trigger somewhere?
0
Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

 
LVL 13

Expert Comment

by:numberkruncher
ID: 22832035
The code I sent you should work fine with VS2008 without any changes...seems odd. Have you tried to use the code that I provided as is before attempting to integrate into your own project? If so, did that work?

If your not getting anything, then it is possible that the "menus.xml" file is not being found.

Also, the event handling code within the code I provided requires that the menu functionality is within a WebControl.
0
 
LVL 3

Author Comment

by:Reddgum
ID: 22832103
I did place the code inside of a web control - in fact, I created a brand new ASP.NET 3.5 project just to watch your code in action. The path to menus.xml is in default directory according to your code, so that's where it sits.

I'll take another pass through, but except for creating the project, everything is exactly as you placed it above.

If need be, I can give you one of my email addy's and send the project outside of EE.

Thanks,

-Red
0
 
LVL 3

Author Comment

by:Reddgum
ID: 22832129
BTW, the code isn't even going to find the xml file, as the program never executes the OnPrerender() method - I have a breakpoint in _every_ method with code, and none of them are visited.
0
 
LVL 13

Expert Comment

by:numberkruncher
ID: 22832145
Yeah sure, if you do that I will send you the ZIP file. That way all you need to do is unzip away and select that project folder as your website.
0
 
LVL 3

Author Comment

by:Reddgum
ID: 22832195
aha.

Found the culprit. How VERY strange.

When I created the project, I gave it the name "MenuTest" -- only one file had the namespace declaration, the rest were missing it, even the web control that was created as a part of the project.

I'll take this one as my bad - it's unlikely VS2008 is to blame.  Ok, now I'm exploring the operation and should have some feedback in a bit.

0
 
LVL 13

Expert Comment

by:numberkruncher
ID: 22832197
If you add your email address as a picture in your original question, you can remove it afterwards to prevent spam.
0
 
LVL 3

Author Comment

by:Reddgum
ID: 22832248
Looks like this will work for what I'm presently doing. It's not the pretty interface I'd originally thought up, but it's workable and is extensible, so you get the points.

Thank you for your time, patience and expertise.

-Red
0
 
LVL 3

Author Closing Comment

by:Reddgum
ID: 31510945
Good job - this will get me going on the right path. If they want a prettier interface, I can work it over at some later point in time - once I've had a chance to fully read up on server side controls!  Thanks!
0
 
LVL 13

Expert Comment

by:numberkruncher
ID: 22832294
No problem!

You can easily add CSS styling capabilities to this to get advanced presentations.
When menu items are created just give them CssClass values.

For root items: linkItem.CssClass = 'rootItem'
For sub items: linkItem.CssClass = 'subItem'

And then for the outer control itself: myControl.CssClass = 'navMenu'
0

Featured Post

Maximize Your Threat Intelligence Reporting

Reporting is one of the most important and least talked about aspects of a world-class threat intelligence program. Here’s how to do it right.

Join & Write a Comment

Suggested Solutions

Just a quick little trick I learned recently.  Now that I'm using jQuery with abandon in my asp.net applications, I have grown tired of the following syntax:      (CODE) I suppose it just offends my sense of decency to put inline VBScript on a…
Today I had a very interesting conundrum that had to get solved quickly. Needless to say, it wasn't resolved quickly because when we needed it we were very rushed, but as soon as the conference call was over and I took a step back I saw the correct …
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.
Polish reports in Access so they look terrific. Take yourself to another level. Equations, Back Color, Alternate Back Color. Write easy VBA Code. Tighten space to use less pages. Launch report from a menu, considering criteria only when it is filled…

744 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

11 Experts available now in Live!

Get 1:1 Help Now