我构建了一个名为Menu的简单控件:
namespace MyControls
{
public class MenuItem
{
public MenuItem()
{
Visible = true;
}
[Localizable(true)]
public string Text { get; set; }
[Localizable(false)]
public string Link { get; set; }
[DefaultValue(true)]
public bool Visible { get; set; }
}
public class MenuDesigner : System.Web.UI.Design.ControlDesigner
{
...
}
[ParseChildren(true, "Items")]
[PersistChildren(false)]
[Designer(typeof(MenuDesigner))]
public class Menu : Control
{
...
public Menu()
{
}
...
private List<MenuItem> _items = new List<MenuItem>();
[PersistenceMode(PersistenceMode.InnerProperty)]
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public List<MenuItem> Items
{
get
{
return _items;
}
}
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
... // More Controls.
list = new BulletedList();
list.DisplayMode = BulletedListDisplayMode.HyperLink;
this.Controls.Add(list);
foreach (var mi in _items)
{
list.Items.Add(new ListItem(mi.Text, Page.Request.CreateUrl(mi.Link)));
}
}
}
}
我以这种方式在我的页面中使用它:
<my:Menu ID="menu" runat="server" Text="MenuTitle">
<my:MenuItem Text="text" Link="link1.aspx">
</my:MenuItem>
<my:MenuItem Text="text2" Link="link2.aspx">
</my:MenuItem>
</my:Menu>
这很有效。没问题。当我切换到Designer视图时,我以我的MenuDesigner呈现它的方式看到Control。使用CTRL-K重新格式化,CTRL-D可以正常工作。运行我的WebPage按照我预期的方式呈现给菜单。
但是:当我在DesingView中点击菜单项“工具” - &gt; “生成本地资源”我得到了这个结果:
<my:Menu ID="menu" runat="server" Text="MenuTitle"
meta:resourcekey="menuResource9">
<my:MenuItem Text="text" Link="link1.aspx">
</my:MenuItem>
<my:MenuItem Text="text2" Link="link2.aspx">
</my:MenuItem>
<Items>
<my:MenuItem Text="text" Link="link1.aspx" meta:resourcekey="MenuItemResource10"></my:MenuItem>
<my:MenuItem Text="text2" Link="link2.aspx" meta:resourcekey="MenuItemResource11"></my:MenuItem>
</Items>
</my:Menu>
哪些属性缺失/错误?我查看了ListBox,它也解析了子项,我觉得我的控件也在做同样的事情。
我发现的唯一差异是:
这不是我愿意出售的控件,只适合我。我不需要任何编辑器或Desinger,我正在手工编写HTML / ASP.NET标记。
我正在使用Visual Studio 2008,.NET 3.5。
感谢任何提示,帮助或Sulutions!
答案 0 :(得分:1)
IMO,您的代码不正确。因为,您未在IStateManager
中实施MenuItem
。在这种情况下,通用列表也不是有效类型。您必须编写实现IStateManager
或使用StateManagedCollection
的自定义集合。
<强>菜单项强>
public class MenuItem : IStateManager
{
private StateBag _viewState;
private bool _isTrackingViewState;
public string Text
{
get { return (string)ViewState["Text"] ?? string.Empty; }
set { ViewState["Text"] = value; }
}
public void SetDirty()
{
if (this._viewState != null)
this._viewState.SetDirty(true);
}
protected virtual StateBag ViewState
{
get
{
if (this._viewState == null)
{
this._viewState = new StateBag(true);
if (this._isTrackingViewState)
((IStateManager)this._viewState).TrackViewState();
}
return this._viewState;
}
}
bool IStateManager.IsTrackingViewState
{
get { return this._isTrackingViewState; }
}
void IStateManager.LoadViewState(object state)
{
if (state != null)
((IStateManager)this.ViewState).LoadViewState(state);
}
object IStateManager.SaveViewState()
{
if (this._viewState != null)
return ((IStateManager)this._viewState).SaveViewState();
return null;
}
void IStateManager.TrackViewState()
{
this._isTrackingViewState = true;
if (this._viewState != null)
((IStateManager)this._viewState).TrackViewState();
}
}
<强> MenuItemCollection 强>
public class MenuItemCollection : StateManagedCollection
{
public MenuItem this[int index]
{
get { return (MenuItem)((IList)this)[index]; }
}
public int Add(MenuItem item)
{
return ((IList)this).Add(item);
}
public void Remove(MenuItem item)
{
((IList)this).Remove(item);
}
// Write Insert and RemoveAt methods
protected override void SetDirtyObject(object o)
{
((MenuItem)o).SetDirty();
}
}
菜单强>
[ParseChildren(true, "Items"), PersistChildren(false)]
public class Menu : Control
{
private MenuItemCollection _items;
[PersistenceMode(PersistenceMode.InnerDefaultProperty), MergableProperty(false)]
public MenuItemCollection Items
{
get
{
if (this._items == null)
{
this._items = new MenuItemCollection();
if (base.IsTrackingViewState)
((IStateManager)this._items).TrackViewState();
}
return this._items;
}
}
protected override void TrackViewState()
{
base.TrackViewState();
if (this._items != null)
((IStateManager)this._items).TrackViewState();
}
protected override void LoadViewState(object savedState)
{
Pair states = (Pair)savedState;
base.LoadViewState(states.First);
if (states.Second != null)
((IStateManager)this.Items).LoadViewState(states.Second);
}
protected override object SaveViewState()
{
Pair states = new Pair();
states.First = base.SaveViewState();
if (this._items != null)
states.Second = ((IStateManager)this._items).SaveViewState();
return states;
}
}
注意:我没有测试上面的代码。
无论如何,在我之前还有另一个答案,我的选择是正确的,但已被删除。您已将PersistenceMode
Items
属性设置为InnerProperty
。因此,您必须按如下方式编写标记。
<my:Menu ID="menu" runat="server" Text="MenuTitle">
<Items>
<my:MenuItem Text="text" Link="link1.aspx" />
<my:MenuItem Text="text2" Link="link2.aspx" />
</Items>
</my:Menu>