Bonjour,
J'ai un problème que je n'arrive pas à résoudre depuis 3 jours : j'ai créé un WebControl dont le but est de m'afficher un cadre dans la page contenant une liste de liens. Je l'ai appelé LinkBox, et je le peuple d'une liste de LinkBoxItem, contenant chacun un titre, une url, un target (frame destination) et une description. Afin de pouvoir peupler la liste dans le code source de la page, je souhaite pouvoir include des objets LinkBoxItem entre les balises de l'objet LinkBox, comme on peuplerait une ListBox ...
Voici le code source du contrôle LinkBox :
using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebControlLibrary1
{
[DefaultProperty("Text")]
[ToolboxData("<{0}:LinkBox runat=server></{0}:LinkBox>")]
[ControlBuilder(typeof(LinkBoxControlBuilder))]
[ParseChildren(true, "Items")]
[PersistChildren(true)]
public class LinkBox : WebControl
{
//private List<LinkBoxItem> _items;
private ArrayList _items2 = new ArrayList();
public LinkBox() : base()
{
//_items = new List<LinkBoxItem>();
_items2 = new ArrayList();
ViewState["Items"] = _items2;
}
//[Bindable(true)]
[Category("Appearance")]
[Localizable(false)]
[PersistenceMode(PersistenceMode.InnerDefaultProperty)]
public ArrayList Items
{
get { return (_items2); }
set { _items2 = value; }
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Text
{
get
{
String s = (String)ViewState["Text"];
return ((s == null) ? String.Empty : s);
}
set { ViewState["Text"] = value; }
}
[Bindable(true)]
[Category("Appearance")]
[DefaultValue("")]
[Localizable(true)]
public string Title
{
get
{
String s = (String)ViewState["Title"];
return ((s == null) ? String.Empty : s);
}
set { ViewState["Title"] = value; }
}
protected override void AddParsedSubObject(object obj)
{
if (obj is LinkBoxItem)
Items.Add((LinkBoxItem)obj);
}
protected override void RenderContents(HtmlTextWriter output)
{
ViewState["items"] = _items2;
output.Write("<div class=\"cadretitre\">");
output.Write("<div class=\"cadretitrepuce\">");
output.Write("<img src=\"images/fly_small.gif\">");
output.Write("</div>");
output.Write("<h2> " + Title + " </h2>");
output.Write("</div>");
output.Write("<div class=\"cadre\">");
output.Write("<h3> " + Text + " </h3>");
output.Write("<p>");
output.Write("<br />");
foreach(LinkBoxItem itm in Items)
{
output.Write("<a href=\"" + itm.Url + "\" target=\"" + itm.Target + "\">" + itm.Title + "</a>");
if (itm.Desc.Length > 0)
output.Write(", " + itm.Desc);
output.Write("<br />");
}
output.Write("</p>");
output.Write("</div>");
}
}
}
Voici le code source de LinkBoxItem :
using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebControlLibrary1
{
public class LinkBoxItem
{
private string _title;
private string _url;
private string _target;
private string _desc;
public LinkBoxItem() : base()
{
_title = "";
_url = "";
_target = "";
_desc = "";
}
public override string ToString()
{
return (_title);
}
#region Properties
public string Desc
{
get { return (_desc); }
set { _desc = value; }
}
public string Target
{
get { return (_target); }
set { _target = value; }
}
public string Title
{
get { return (_title); }
set { _title = value; }
}
public string Url
{
get { return (_url); }
set { _url = value; }
}
#endregion
}
}
Et enfin le code source du LinkBoxControlBuilder :
using
System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebControlLibrary1
{
public class LinkBoxControlBuilder : ControlBuilder
{
public override Type GetChildControlType(string tagName, System.Collections.IDictionary attribs)
{
if (tagName.ToLower() == "linkboxitem")
return typeof(LinkBoxItem);
return null;
}
}
}
Exemple d'utilisation :
<SMWeb:LinkBox ID="LinkBox1" runat="server" Text="Ceci est un petit texte descriptif de la boite ..." Title="Titre de la boite">
<SMWeb:LinkBoxItem Target="_blank" Desc="" Title="Site 1" Url="http://www.site1.com/"></SMWeb:LinkBoxItem>
<SMWeb:LinkBoxItem Target="_blank" Desc="" Title="Site 2" Url="http://www.site2.com/"></SMWeb:LinkBoxItem>
<SMWeb:LinkBoxItem Target="_blank" Desc="le meilleur !" Title="Site 3" Url="http://www.site3.com/"></SMWeb:LinkBoxItem>
</SMWeb:LinkBox>
A l'exécution, cela donne l'affichage suivant :

Ce qui est exactement le comportement souhaité (ok la feuille de style n'est pas appliquée pour le moment mais là n'est pas le problème ...)
Mon problème, c'est que dans le designer, j'obtiens ça :

Et ça c'est pas normal ...
Avant, je mettais "ParseChildren(false)" au niveau du WebControl, et du coup il ne lisait pas les tags des éléments LinkBoxItem, par contre j'arrivais à peupler la propriété Items via la fenêtre propriétés de Visual Studio, cependant, il ne rajoutait pas les tags dans le code source de la page, ce qui fait qu'une fois rechargé la fenêtre, la liste était vide ...
Vous constaterez que j'utilisais au début une List<LinkBoxItem> que j'ai temporairement remplacé par une ArrayList pensant que c'était le seul type que pouvait utiliser ASP.NET via l'attribut ParseChildren ...
Qu'est ce que j'ai fait faux ? Juste un oubli quelque part ou est-ce que je n'ai rien compris à la méthode en ASP.NET ?
Pour info j'ai fait un paquet d'ASP classique et j'ai sauté l'étape ASP.NET 1.x ...
Merci pour vos réponses !
Stéphane.