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>
精彩评论