VS 2008, ASP.NET: создание локальных ресурсов - PullRequest
0 голосов
/ 04 февраля 2010

Я создал простой элемент управления под названием 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. Переформатирование с помощью CTRL-K, CTRL-D работает. Запуск моей веб-страницы отображается в Menu так, как я ожидал.

Но: когда я нажимаю в 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
  • У меня нет редактора или ControlBuilder или TypeConverter для моего MenuItem, ListBox делает.

Это не тот элемент управления, который я готов продать, а только для меня. Мне не нужен редактор или редактор, я пишу разметку HTML / ASP.NET вручную.

Я использую Visual Studio 2008, .NET 3.5.

Спасибо за любые подсказки, помощь или решения!

1 Ответ

1 голос
/ 04 февраля 2010

IMO, ваш код неверен. Потому что вы не реализовали IStateManager в MenuItem. Также универсальный список не является допустимым типом в этом случае. Вы должны написать собственную коллекцию, которая реализует IStateManager или использовать StateManagedCollection.

MenuItem

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>
...