简体   繁体   中英

Problem in creating a ServerControl in ASP.NET , C#?

I'm working on a ServerControl (SuperFish Menu).
Below is my codes.

Menu.cs

[AspNetHostingPermission(SecurityAction.Demand, Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level = AspNetHostingPermissionLevel.Minimal)]
[ParseChildren(true, "MenuItems")]
[PersistChildren(true)]
[ToolboxData("<{0}:Menu runat=\"server\"></{0}:Menu>")]
public class Menu : WebControl, INamingContainer
{
    #region Fields

    List<MenuItem> _MenuItems;

    #endregion

    #region Properties

    public VerOrHor VerticalOrHorizontal { get; set; }

    public string Main_ul_CssClass { get; set; }

    [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
    public animation AnimationItems { get; set; }

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
    public List<MenuItem> MenuItems
    {
        get
        {
            if (_MenuItems == null)
            {
                _MenuItems = new List<MenuItem>();
            }
            return _MenuItems;
        }
    }

    string _AnimationType
    {
        get
        {
            switch (this.AnimationItems.AnimationType)
            {
                case AnimationType.Opacity_Height:
                    return "animation:{opacity:'show',height:'show'}";
                case AnimationType.Opacity:
                    return "animation:{opacity:'show'}";
                case AnimationType.Height:
                    return "animation:{height:'show'}";
                default:
                    return "animation:{opacity:'show',height:'show'}";
            }
        }
    }

    string _AnimationSpeed
    {
        get
        {
            switch (this.AnimationItems.AnimationSpeed)
            {
                case AnimationSpeed.Fast:
                    return "speed:Fast";
                case AnimationSpeed.Normal:
                    return "speed:Normal";
                case AnimationSpeed.Slow:
                    return "speed:Slow";
                default:
                    return "speed:Fast";
            }
        }
    }

    #endregion

    #region Methods

    public override void RenderBeginTag(HtmlTextWriter writer)
    {

    }

    public override void RenderEndTag(HtmlTextWriter writer)
    {

    }

    protected override void AddAttributesToRender(HtmlTextWriter writer)
    {
        base.AddAttributesToRender(writer);
    }

    protected override void OnPreRender(EventArgs e)
    {
        base.OnPreRender(e);

        #region Adding Script & link Tags

        HtmlGenericControl jquery = new HtmlGenericControl("script");
        jquery.Attributes.Add("type", "text/javascript");
        jquery.Attributes.Add("src", Page.ClientScript.GetWebResourceUrl(typeof(Menu), "JQueryMenu.JavaScriptFiles.jquery_1_4_3.js"));
        jquery.EnableViewState = false;
        Page.Header.Controls.Add(jquery);

        HtmlGenericControl hoverIntent = new HtmlGenericControl("script");
        hoverIntent.Attributes.Add("type", "text/javascript");
        hoverIntent.Attributes.Add("src", Page.ClientScript.GetWebResourceUrl(typeof(Menu), "JQueryMenu.JavaScriptFiles.hoverIntent.js"));
        hoverIntent.EnableViewState = false;
        Page.Header.Controls.Add(hoverIntent);

        HtmlGenericControl jquery_bgiframe_min = new HtmlGenericControl("script");
        jquery_bgiframe_min.Attributes.Add("type", "text/javascript");
        jquery_bgiframe_min.Attributes.Add("src", Page.ClientScript.GetWebResourceUrl(typeof(Menu), "JQueryMenu.JavaScriptFiles.jquery_bgiframe_min.js"));
        jquery_bgiframe_min.EnableViewState = false;
        Page.Header.Controls.Add(jquery_bgiframe_min);

        HtmlGenericControl superfish = new HtmlGenericControl("script");
        superfish.Attributes.Add("type", "text/javascript");
        superfish.Attributes.Add("src", Page.ClientScript.GetWebResourceUrl(typeof(Menu), "JQueryMenu.JavaScriptFiles.superfish.js"));
        superfish.EnableViewState = false;
        Page.Header.Controls.Add(superfish);

        HtmlGenericControl supersubs = new HtmlGenericControl("script");
        supersubs.Attributes.Add("type", "text/javascript");
        supersubs.Attributes.Add("src", Page.ClientScript.GetWebResourceUrl(typeof(Menu), "JQueryMenu.JavaScriptFiles.supersubs.js"));
        supersubs.EnableViewState = false;
        Page.Header.Controls.Add(supersubs);

        HtmlGenericControl csslink = new HtmlGenericControl("link");
        csslink.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl
            (typeof(Menu), "JQueryMenu.CSS.superfish.css"));
        csslink.ID = "NavigationMenu";
        csslink.Attributes.Add("type", "text/css");
        csslink.Attributes.Add("rel", "stylesheet");
        csslink.EnableViewState = false;
        Page.Header.Controls.Add(csslink);

        if (this.VerticalOrHorizontal == VerOrHor.Vertical)
        {
            HtmlGenericControl csslink01 = new HtmlGenericControl("link");
            csslink01.Attributes.Add("href", Page.ClientScript.GetWebResourceUrl
                (typeof(Menu), "JQueryMenu.CSS.superfish-vertical.css"));
            csslink01.Attributes.Add("type", "text/css");
            csslink01.Attributes.Add("rel", "stylesheet");
            csslink01.EnableViewState = false;
            Page.Header.Controls.Add(csslink01);
        }

        #endregion
    }

    protected override void RenderContents(HtmlTextWriter output)
    {
        output.Write(CreateMenuHtmlTags().ToString());
    }

    StringBuilder CreateMenuHtmlTags()
    {
        if (_MenuItems == null || _MenuItems.Count <= 0)
            throw new Exception("Please Fill the control with <MenuItem> tags");

        StringBuilder Html = new StringBuilder("");

        #region Add <Script>

        if (String.IsNullOrEmpty(Main_ul_CssClass))
            Html.Append("<script>$(document).ready(function() { $(\"ul.sf-menu\").superfish({pathLevels:    1,");
        else
            Html.Append("<script>$(document).ready(function() { $(\"ul." + Main_ul_CssClass + "\").superfish({ pathLevels:    1,");

        if (AnimationItems == null)
            Html.Append("delay:1000, animation:{opacity:'show',height:'show'}, speed:'normal', autoArrows:  true, dropShadows: true}); });</script>");
        else
        {
            Html.Append("delay:" + AnimationItems.Delay.Trim() + ",");
            Html.Append(_AnimationType + ",");
            Html.Append(_AnimationSpeed + ",");
            Html.Append("dropShadows:  " + AnimationItems.DropShadow.ToString() + ",");
            Html.Append(@"autoArrows:  false});});</script>");
        }

        #endregion

        if (String.IsNullOrEmpty(Main_ul_CssClass))
            Html.Append("<ul class=\"sf-menu sf-js-enabled sf-shadow\" id='sample-menu-1'>");
        else
            Html.Append("<ul class=\"" + Main_ul_CssClass + "\" id='sample-menu-1'>");

        foreach (MenuItem item in _MenuItems)
        {
            if (item.SubMenuItems != null || item.SubMenuItems.Count > 0)
            {
                if (!string.IsNullOrEmpty(item.li_CssClass))
                    Html.Append("<li class=\"" + item.li_CssClass + "\">");
                else
                    Html.Append("<li>");
                Html.Append("<a href=\"" + item.href + "\">" + item.Text.Trim() + "</a>");
                ParseSubMenuItems(ref Html, item);
                Html.Append("</li>");
            }
            else
                Html.Append("<li><a href=\"" + item.href + "\">" + item.Text.Trim() + "</a></li>");
        }
        Html.Append("</ul>");

        return Html;
    }

    void ParseSubMenuItems(ref StringBuilder Html, MenuItem menuItems)
    {
        if (menuItems == null || menuItems.SubMenuItems.Count == 0) return;

        Html.Append("<ul class=\"" + menuItems.ul_CssClass.Trim() + "\" style=\"display: none; visibility: hidden;\">");
        foreach (MenuItem item in menuItems.SubMenuItems)
        {
            if (item.SubMenuItems != null || item.SubMenuItems.Count > 0)
            {
                if (!string.IsNullOrEmpty(item.li_CssClass))
                    Html.Append("<li class=\"" + item.li_CssClass + "\">");
                else
                    Html.Append("<li>");
                Html.Append("<a href=\"" + item.href + "\">" + item.Text.Trim() + "</a>");
                ParseSubMenuItems(ref Html, item);
                Html.Append("</li>");
            }
            else
                Html.Append("<li><a href=\"" + item.href + "\">" + item.Text.Trim() + "</a></li>");
        }
        Html.Append("</ul>");
    }

    #endregion
}

public enum VerOrHor
{
    Vertical,
    Horizontal
}

public class MenuItemsCollectionEditor : CollectionEditor
{
    public MenuItemsCollectionEditor(Type type)
        : base(type)
    {
    }

    protected override bool CanSelectMultipleInstances()
    {
        return false;
    }

    protected override Type CreateCollectionItemType()
    {
        return typeof(MenuItem);
    }
}

MenuItem.cs

[PersistChildren(true)]
[ParseChildren(true, "SubMenuItems")]
public class MenuItem : Control, INamingContainer
{
    #region Fields

    List<MenuItem> _SubMenuItems;

    #endregion

    #region Properties

    [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
    //[Editor(typeof(SubMenuItemsCollectionEditor), typeof(UITypeEditor))]
    [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
    public List<MenuItem> SubMenuItems
    {
        get
        {
            if (_SubMenuItems == null)
            {
                _SubMenuItems = new List<MenuItem>();
            }
            return _SubMenuItems;
        }
    }

    [DefaultValue("MenuItem")]
    public string Text { get; set; }

    [DefaultValue("")]
    [Description("<ul /> css class")]
    public string ul_CssClass { get; set; }

    [DefaultValue("")]
    [Description("<li /> css class")]
    public string li_CssClass { get; set; }

    [DefaultValue("#")]
    [Description("<a /> href attribute")]
    public string href { get; set; }

    [TemplateContainer(typeof(MenuItem))]
    [PersistenceMode(PersistenceMode.InnerDefaultProperty)]
    public ITemplate Template { get; set; }

    #endregion
}

public class SubMenuItemsCollectionEditor : CollectionEditor
{
    public SubMenuItemsCollectionEditor(Type type)
        : base(type)
    {
    }

    protected override bool CanSelectMultipleInstances()
    {
        return false;
    }

    protected override Type CreateCollectionItemType()
    {
        return typeof(MenuItem);
    }
}

animation.cs

public class animation
{
    [DefaultValue("1000")]
    [NotifyParentProperty(true)]
    public string Delay { get; set; }

    [DefaultValue("Opacity_Height")]
    [NotifyParentProperty(true)]
    public AnimationType AnimationType { get; set; }

    [DefaultValue("fast")]
    [NotifyParentProperty(true)]
    public AnimationSpeed AnimationSpeed { get; set; }

    [DefaultValue("false")]
    [NotifyParentProperty(true)]
    public bool DropShadow { get; set; }
}

public enum AnimationType
{
    Opacity_Height,
    Opacity,
    Height
}

public enum AnimationSpeed
{
    Fast,
    Normal,
    Slow
}

It works fine with below code (Without AnimationItems ):

<MdsMenu:Menu ID="Menu1" runat="server">
    <MdsMenu:MenuItem Text="MenuItem 01"></MdsMenu:MenuItem>
    <MdsMenu:MenuItem Text="MenuItem 02"></MdsMenu:MenuItem>
    <MdsMenu:MenuItem Text="MenuItem 03" />
</MdsMenu:Menu>

But when I add AnimationItems tag like the following code I receive the Exception :

Exception : Error Creating Control - Menu1Type 'JQueryMenu.Menu' does not have a public property named 'MenuItem'.

创建控件时出错

<MdsMenu:Menu ID="Menu1" runat="server">
    <AnimationItems AnimationSpeed="Fast" AnimationType="Opacity_Height" DropShadow="true" Delay="1000" />
    <MdsMenu:MenuItem Text="MenuItem 01"></MdsMenu:MenuItem>
    <MdsMenu:MenuItem Text="MenuItem 02"></MdsMenu:MenuItem>
    <MdsMenu:MenuItem Text="MenuItem 03" />
</MdsMenu:Menu>

You have two properties decorated with PersistenceMode.InnerDefaultProperty , and:

Only one property can be designated the default property.

I'd suggest you decorate your AnimationItems property with PersistenceMode.InnerProperty instead:

[PersistenceMode(PersistenceMode.InnerProperty)]
public animation AnimationItems
{
    get;
    set;
}

EDIT: The above is not enough. I got the code to work with some tweaks:

First, disable child persistence and remove the defaultProperty argument from the [ParseChildren] attribute:

[AspNetHostingPermission(SecurityAction.Demand,
    Level = AspNetHostingPermissionLevel.Minimal)]
[AspNetHostingPermission(SecurityAction.InheritanceDemand,
    Level = AspNetHostingPermissionLevel.Minimal)]
[ParseChildren(true)]
[ToolboxData("<{0}:Menu runat=\"server\"></{0}:Menu>")]
public class Menu : WebControl, INamingContainer
{
}

Then, decorate the AnimationItems property with PersistenceMode.InnerProperty , as suggested above. Do the same to MenuItems and remove its [DesignerSerializationVisibility] attribute:

[PersistenceMode(PersistenceMode.InnerProperty)]
public animation AnimationItems { get; set; }

[PersistenceMode(PersistenceMode.InnerProperty)]
public List<MenuItem> MenuItems
{
}

Finally, add a <MenuItems> element to your markup:

<MdsMenu:Menu ID="Menu1" runat="server">
    <AnimationItems AnimationSpeed="Fast" AnimationType="Opacity_Height"
        DropShadow="true" Delay="1000" />
    <MenuItems>
        <MdsMenu:MenuItem Text="MenuItem 01"></MdsMenu:MenuItem>
        <MdsMenu:MenuItem Text="MenuItem 02"></MdsMenu:MenuItem>
        <MdsMenu:MenuItem Text="MenuItem 03" />
    </MenuItems>
</MdsMenu:Menu>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM