2010-02-04 3 views
0

J'ai construire un contrôle simple appelé Menu:VS 2008, ASP.NET: Générer des ressources locales

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))); 
      } 
     } 
    } 
} 

Je l'utilise dans ma page de cette façon:

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

Cela fonctionne. Pas de problème. Lorsque je passe à la vue Designer, je vois le contrôle de la façon dont mon MenuDesigner le rend. Reformater avec CTRL-K, CTRL-D fonctionne. Exécution de mon WebPage rend à Menu la façon dont je l'attendais.

Mais: quand je frappe dans le DesingView l'élément de menu « Outils » -> « Générer des ressources locales » Je reçois ce résultat:

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

Quels attributs sont manquants/mal? J'ai regardé dans ListBox, qui analyse également des éléments enfants et j'ai le sentiment que mon contrôle fait la même chose.

Les seules différences que j'ai trouvé:

  • J'utilise une liste générique, ListBox a son propre type de collection pour ListItems
  • Je n'ai pas éditeur ou ControlBuilder ou TypeConverter pour mon MenuItem, ListBox ne .

Ce n'est pas un contrôle que je suis prêt à vendre, c'est seulement pour moi. Je n'ai pas besoin d'éditeur ou de Desinger, j'écris à la main le balisage HTML/ASP.NET. Je utilise Visual Studio 2008, .NET 3.5.

Merci pour tous les conseils, l'aide ou les solutions!

Répondre

1

IMO, votre code est incorrect. Parce que, vous n'avez pas implémenté IStateManager dans le MenuItem. De plus, la liste générique n'est pas un type valide dans ce cas. Vous devez écrire une collection personnalisée qui implémente IStateManager ou utiliser 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(); 
    } 

} 

Menu

[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; 
    } 

} 

Note: Je n'ai pas testé le code ci-dessus.

De toute façon, il y avait une autre réponse avant la mienne qui était correcte dans mon opition, mais a été supprimée. Vous avez défini la propriété PersistenceMode de Items sur InnerProperty. Ainsi, vous devez écrire le balisage comme suit.

<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> 
+0

Oui! PersistenceMode.InnerDefaultProperty l'a fait! Je vous remercie! BTW: J'ai essayé d'implémenter un StateManagedCollection mais sans chance. OK - J'ai arrêté d'implémenter StateManagedCollection lorsque j'ai lu votre Edit. – Arthur

+0

Oh mec, je suis tellement désolé.Ce point n'est pas le mien. Pour autant que je disais autre utilisateur répondre à votre question. Mais, il a supprimé son message. Quoi qu'il en soit, je vais écrire un exemple simple pour que vous puissiez résoudre le problème ViewState. –

+0

Merci! Dans ce cas, je n'ai pas besoin de corriger le problème viewstate (sans utiliser viewstate) mais j'y trouve un intérêt! Donc: Pas de stress! – Arthur

Questions connexes