VS 2008,ASP.NET:生成本地资源

时间:2010-02-04 14:24:18

标签: asp.net custom-controls designer

我构建了一个名为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,它也解析了子项,我觉得我的控件也在做同样的事情。

我发现的唯一差异是:

  • 我使用的是通用List,ListBox拥有自己的ListItems集合类型
  • 我的MenuItem没有Editor或ControlBuilder或TypeConverter,ListBox没有。

这不是我愿意出售的控件,只适合我。我不需要任何编辑器或Desinger,我正在手工编写HTML / ASP.NET标记。

我正在使用Visual Studio 2008,.NET 3.5。

感谢任何提示,帮助或Sulutions!

1 个答案:

答案 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>