【问题标题】:VS 2008, ASP.NET: Generate Local ResourcesVS 2008,ASP.NET:生成本地资源
【发布时间】:2011-01-13 02:34:05
【问题描述】:

我已经构建了一个名为 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>

这行得通。没问题。当我切换到设计器视图时,我会以 MenuDesigner 呈现它的方式看到控件。使用 CTRL-K 重新格式化,CTRL-D 有效。运行我的网页会以我期望的方式呈现给菜单。

但是:当我在 DesingView 中点击菜单项“工具”->“生成本地资源”时,我得到了这个结果:

<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,它也解析子项,我感觉我的控件也在做同样的事情。

我发现的唯一区别:

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

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

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

感谢任何提示、帮助或解决方案!

【问题讨论】:

    标签: asp.net custom-controls designer


    【解决方案1】:

    IMO,您的代码不正确。因为,您没有在MenuItem 中实现IStateManager。在这种情况下,泛型列表也不是有效类型。您必须编写一个自定义集合来实现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;
        }
    
    }
    

    注意:我没有测试上面的代码。

    无论如何,在我之前有另一个答案在我看来是正确的,但已被删除。您已将Items 属性的PersistenceMode 设置为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>
    

    【讨论】:

    • 是的! PersistenceMode.InnerDefaultProperty 做到了!谢谢!顺便说一句:我尝试实现 StateManagedCollection 但没有运气。好的 - 当我阅读您的编辑时,我停止实施 StateManagedCollection。
    • 天哪,我很抱歉。这一点不是我的。据我所说,其他用户回答您的问题。但是,他删除了他的帖子。无论如何,我会写一个简单的例子给你解决 ViewState 问题。
    • 谢谢!在那种情况下,我不需要修复视图状态问题(不使用视图状态),但我对此很感兴趣!所以:没有压力!
    • @another users 回答:嗯,你看到这可能是正确的方向,你看到帖子被删除了,你重复它,因为你认为它可能是正确的。所以我认为要点是你的:-)
    • 不应该是 if (this._items == null) 而不是 if (this._items != null) in Menu: public MenuItemCollection Items?
    猜你喜欢
    • 2022-11-28
    • 2011-03-22
    • 2010-10-01
    • 1970-01-01
    • 1970-01-01
    • 2012-06-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多