Using custom ControlBuilder to parse deep nested sub controls?

Discussion in 'ASP .Net Web Controls' started by Sky, Jul 9, 2004.

  1. Sky

    Sky Guest

    Hello: Been struggling a little bit today trying to understand how to use
    the ControlBuilder to make a nested menu system.

    If the HTML should look something like:

    <CC:OutlookBar runat=server id=TheMenu>
    <OutlookBarItem IsFolder=true Label=FolderA>
    <OutlookBarItem IsFolder=FALSE Label=Item A.1/>
    <OutlookBarItem IsFolder=FALSE Label=Item A.2/>
    <OutlookBarItem IsFolder=FALSE Label=Item A.3/>
    </OutlookBarItem>
    <OutlookBarItem IsFolder=true Label=FolderB>
    <OutlookBarItem IsFolder=FALSE Label=Item B.1/>
    <OutlookBarItem IsFolder=FALSE Label=Item B.2/>
    <OutlookBarItem IsFolder=FALSE Label=Item B.3/>
    </OutlookBarItem>
    <CC:OutlookBar>


    I found that it was correctly able to handle the HTML parsing as long as
    there was no second level nested layers (ie Items) -- only Folders... (which
    doesn't forbode well for my future ideas of making a recursive menu ....)

    I'm not sure which way to go in the code that follows:
    a) If I keep the ParseChildren(true," OUTLOOKBARITEM) on the OutlookItem,
    it correctly adds nested tags to the _Children IList -- but as
    LiteralControls. Not as OutlookItems...so fails at rendering later.
    b) If I remove it, I get an error saying "TEMPLATES cannot have Properties"
    c) I am wondering if there is a way to append a MyBuilder to the children so
    that it can recurse deeper -- I would think AppendSubBuilder is just for
    that -- but no examples of such on the web.
    d) ...?


    The code parts are as follows:

    [ParseChildren(ChildrenAsProperties =
    false),PersistChildren(true),ControlBuilderAttribute(typeof(MyBuilder))]
    public class OutlookBar(){
    .. . .
    protected override void AddParsedSubObject(Object obj) {
    if (obj is XOutlookBarItem){_Items.Add((XOutlookBarItem)obj);}
    }
    .. . .
    }//Class:End

    [ParseChildren(true,"OUTLOOKBARITEM"),PersistChildren(true),ControlBuilderAt
    tribute(typeof(MyBuilder))]
    public class XOutlookBarItem {
    //private fields
    bool _IsFolder=false;
    string _Label = string.Empty;
    string _Url = string.Empty;
    string _ImgUrl = string.Empty;
    ArrayList _List = new ArrayList();
    //public properties
    public bool IsFolder {get {return _IsFolder;}set{_IsFolder =
    value;}}
    public string Label {get {return _Label;}set{_Label = value;}}
    public string Url {get {return _Url;}set{_Url = value;}}
    public string ImgUrl {get {return _ImgUrl;}set{_ImgUrl = value;}}
    public IList OUTLOOKBARITEM{get{return _List;}}}
    //Constructor:
    public XOutlookBarItem(){}
    }



    And the builder as:

    public class MyBuilder : ControlBuilder {
    public override Type GetChildControlType(string tagName, IDictionary
    attribs) {
    if (tagName.ToUpper().EndsWith("OUTLOOKBARITEM")){
    return typeof(XOutlookBarItem);
    }
    return null;
    }
    public override void AppendLiteralString(string s) {}// Ignores literals
    between rows.
    public override bool AllowWhitespaceLiterals(){return false;}
    public override void AppendSubBuilder(System.Web.UI.ControlBuilder
    subBuilder){
    string tCheck = subBuilder.GetType().ToString();
    //subBuilder = new MyBuilder();
    }
    }


    (Are you still there after such a long intro =;-)?


    PS: I have no idea if it makes any sense to add the
    PersistChildren(true),ControlBuilderAttribute(typeof(MyBuilder)) attributes
    to the OutlookBarItem class, as it is not a Control. Only works with
    controls, right? And that would be handled by the same attributes on the
    parent control (OutlookBar), so it is no use, right? Just checking.


    Thanks!
     
    Sky, Jul 9, 2004
    #1
    1. Advertising

  2. Sky

    Kevin Bilbee Guest

    How did you get this far? What documentation did you read to create your
    control to this point????

    Any help would be great. I am stuck and do not know if I am even in the
    write direction with my code. I would like to read a tutorial about the
    subject with full examples. I have the Developing MS ASP.NET Server
    Controls book that I inherited from a former employee but there is no CD and
    the book kkps refering to the CD for the full example.


    Kevin Bilbee

    "Sky" <> wrote in message
    news:...
    > Hello: Been struggling a little bit today trying to understand how to use
    > the ControlBuilder to make a nested menu system.
    >
    > If the HTML should look something like:
    >
    > <CC:OutlookBar runat=server id=TheMenu>
    > <OutlookBarItem IsFolder=true Label=FolderA>
    > <OutlookBarItem IsFolder=FALSE Label=Item A.1/>
    > <OutlookBarItem IsFolder=FALSE Label=Item A.2/>
    > <OutlookBarItem IsFolder=FALSE Label=Item A.3/>
    > </OutlookBarItem>
    > <OutlookBarItem IsFolder=true Label=FolderB>
    > <OutlookBarItem IsFolder=FALSE Label=Item B.1/>
    > <OutlookBarItem IsFolder=FALSE Label=Item B.2/>
    > <OutlookBarItem IsFolder=FALSE Label=Item B.3/>
    > </OutlookBarItem>
    > <CC:OutlookBar>
    >
    >
    > I found that it was correctly able to handle the HTML parsing as long as
    > there was no second level nested layers (ie Items) -- only Folders...

    (which
    > doesn't forbode well for my future ideas of making a recursive menu ....)
    >
    > I'm not sure which way to go in the code that follows:
    > a) If I keep the ParseChildren(true," OUTLOOKBARITEM) on the OutlookItem,
    > it correctly adds nested tags to the _Children IList -- but as
    > LiteralControls. Not as OutlookItems...so fails at rendering later.
    > b) If I remove it, I get an error saying "TEMPLATES cannot have

    Properties"
    > c) I am wondering if there is a way to append a MyBuilder to the children

    so
    > that it can recurse deeper -- I would think AppendSubBuilder is just for
    > that -- but no examples of such on the web.
    > d) ...?
    >
    >
    > The code parts are as follows:
    >
    > [ParseChildren(ChildrenAsProperties =
    > false),PersistChildren(true),ControlBuilderAttribute(typeof(MyBuilder))]
    > public class OutlookBar(){
    > . . .
    > protected override void AddParsedSubObject(Object obj) {
    > if (obj is XOutlookBarItem){_Items.Add((XOutlookBarItem)obj);}
    > }
    > . . .
    > }//Class:End
    >
    >

    [ParseChildren(true,"OUTLOOKBARITEM"),PersistChildren(true),ControlBuilderAt
    > tribute(typeof(MyBuilder))]
    > public class XOutlookBarItem {
    > //private fields
    > bool _IsFolder=false;
    > string _Label = string.Empty;
    > string _Url = string.Empty;
    > string _ImgUrl = string.Empty;
    > ArrayList _List = new ArrayList();
    > //public properties
    > public bool IsFolder {get {return _IsFolder;}set{_IsFolder =
    > value;}}
    > public string Label {get {return _Label;}set{_Label = value;}}
    > public string Url {get {return _Url;}set{_Url = value;}}
    > public string ImgUrl {get {return _ImgUrl;}set{_ImgUrl = value;}}
    > public IList OUTLOOKBARITEM{get{return _List;}}}
    > //Constructor:
    > public XOutlookBarItem(){}
    > }
    >
    >
    >
    > And the builder as:
    >
    > public class MyBuilder : ControlBuilder {
    > public override Type GetChildControlType(string tagName, IDictionary
    > attribs) {
    > if (tagName.ToUpper().EndsWith("OUTLOOKBARITEM")){
    > return typeof(XOutlookBarItem);
    > }
    > return null;
    > }
    > public override void AppendLiteralString(string s) {}// Ignores

    literals
    > between rows.
    > public override bool AllowWhitespaceLiterals(){return false;}
    > public override void AppendSubBuilder(System.Web.UI.ControlBuilder
    > subBuilder){
    > string tCheck = subBuilder.GetType().ToString();
    > //subBuilder = new MyBuilder();
    > }
    > }
    >
    >
    > (Are you still there after such a long intro =;-)?
    >
    >
    > PS: I have no idea if it makes any sense to add the
    > PersistChildren(true),ControlBuilderAttribute(typeof(MyBuilder))

    attributes
    > to the OutlookBarItem class, as it is not a Control. Only works with
    > controls, right? And that would be handled by the same attributes on the
    > parent control (OutlookBar), so it is no use, right? Just checking.
    >
    >
    > Thanks!
    >
    >
    >
     
    Kevin Bilbee, Jul 12, 2004
    #2
    1. Advertising

  3. Sky

    Sky Guest

    Hi Kevin:

    Read Building ASP.NET Server Controls -- Apress. Damn good.

    As for how to get this far (and further since I was able to solve it a
    couple of hours after I posted :) ) These are the points I've distilled so
    far:

    a) There are several levels of controls:
    i) basic control that inherits from Control. That means you generally
    have to implement IPostBackEventHandler and/or IPostBackDataHandler (i think
    those are the names -- atleast they are something like that). Plus you have
    to have a pretty good idea of Styles/ViewState...therefore, to solve that
    kind of headache, I suggest moving up the food chain to:
    ii) basic control that inherits from WebControl. That's pretty easy...
    An obvious example would be inherit and extend something like Label.
    iii) Composite control -- now things get a little interesting here.
    Again, I have experimented with enheriting the wrapper control from
    Control -- but frankly, inheriting from WebControl makes it much easier.
    iv) Control that has sub-elements. Eg: a SELECT like control that has
    OPTIONS (or Asp:ListItem). I'll come back to this in a second.
    v) Controls that have sub templates
    vi) Controls that have nested Sub-Elements (which is what the original
    post was about).


    This all took me a little to 'see'/figure out, hence why I am emphasizing
    that not all controls are the same -- the last 3 are the ones we are talking
    about now.

    Lets go back to the iv) first -- I was making a Combo (editable pulldown),
    and I was having a lot of trouble on figuring out how to add OPTIONS to
    it... Turns out that the secret is the attribute
    [ParseChildren] attribute...that you put above the Control : WebControl def.
    There are 3 ways it can be written - and they do different things:

    a) ParseChildren(false) -- means "Any subelements are NOT Properties - - so
    has to fit other criteria".
    b) ParseChildren(true) -- means "Parse child tags and try to match them to
    Properties. Something like

    <cc1:MyControl>
    <ForeColor >
    </cc1:MyControl>
    (or something like that -- frankly I havn't used it this way yet so I'm not
    sure how that would look-- but it's something like this...)

    and finally
    c) ParseChildren(true,"ITEMS") -- which is the beginning of where things get
    interesting. This states Parse sub tags as properties -- and if you see
    <items> then add then to a collection given by the control.
    in other words this would be valid if

    <cc1:MyControl>
    <asp:listItem Text="John">
    <asp:listItem Text="Sam">
    <asp:listItem Text="Mary">
    </cc1:MyControl>

    What this will do is take all sub elements found, and try to add it to a
    public property you have provided in your control that must be called Items
    since you declared in the attribute that it would be so:

    public ArrayList Items {get {return _List;}}

    Did you get that part? -- it takes all tags and shoves them in List... in
    other words this is valid to -- although probably not at all what you want:
    <cc1:MyControl>
    <asp:listItem Text="John">
    <asp:listItem Text="Sam">
    <asp:Label Text="Damn">
    </cc1:MyControl>

    This will still stick the item in the Items arrayList -- but probably cause
    you headaches at Render() time.

    Therefore -- although that looked sooo easy -- it's usually a red herring --
    so everything I just said ignore, and let's point out a more flexible, but
    managaed, way:

    This time make the attribute like this
    [ParseChildren(ChildrenAsProperties = false)]


    AND override the Control's AddParsedSubObject method to only add items of a
    specific type:

    protected override void AddParsedSubObject(Object obj) {
    if (obj is ListItem){_Items.Add((ListItem)obj);}else {/*ignore
    me*/}
    }

    See where this is going? AddParsedSubObject always happened - -but now you
    are controlling which items to add... You can tell it to ignore the Label --
    or any Literals that got in there by accident/whatever.

    We are starting to get where we want -- although it ticks me off that I have
    to use "asp:ListItem" rather than OPTION -- it's much more verbose, and
    frankly I'm sure that I will type it wrong...so...I have to figure out a way
    to get it to accept tags that start with <OPTION....But...


    There is still one hitch though....ASP is not very smart: It will recognize
    any item that is ASP: tagged (eg: ListItems) but is stupid as a plank if you
    want it to recognize something like plain HTML. And anything it doesn't
    recognize it will treat as HtmlGenericControl.

    In other words, if you typed something like

    <cc1:MyControl>
    <option Text="John"/>
    <option Text="Sam"/>
    <option Text="Mary"/>
    </cc1:MyControl>

    AddParsedSubObject WILL be called -- but not 3 times -- only once!!!, being
    passed one big HtmlGenericControl whose contents are '<option
    Text="John"/><option Text="Sam"/><option Text="Mary"/>"...
    Ie bluddy useless.

    The problem is because ASP has a default controlBuilder -- a fancy name for
    customparser? -- that only looks for Asp tags. You have to make one that is
    a bit smarter, looking out for your own tags.
    Good news is that it is really simple -- in essense you are asking it to
    look out for startTags that match what you are looking for:

    a) Stick this on your control btw:
    ControlBuilderAttribute(typeof(MyBuilder))

    b) An example of a Builder
    > > public class MyBuilder : ControlBuilder {
    > > public override Type GetChildControlType(string tagName, IDictionary
    > > attribs) {
    > > if (tagName.ToUpper().StartsWith("OPTION")) ||

    (tagName.ToUpper().StartsWith("ITEM")) || (tagName.IndexOf("LISTITEM")>-1)){
    > > return typeof(ListItem); <-- notice this line....
    > > }
    > > return null;
    > > }
    > > public override void AppendLiteralString(string s) {}// Ignores

    literals between rows.
    > > public override bool AllowWhitespaceLiterals(){return false;}
    > > public override void AppendSubBuilder(System.Web.UI.ControlBuilder

    subBuilder){
    > > string tCheck = subBuilder.GetType().ToString();
    > > //subBuilder = new MyBuilder();
    > > }
    > > }



    With this in place you can then type:

    <cc1:MyControl>
    <option Text="John"/>
    <ITEM Text="Sam"/>
    <option Text="Mary"/>
    <asp:listitem Text="Mary"/>
    <asp:Label Text="Discard me">
    </cc1:MyControl>


    You will end up with AppendLiteralControl being called 3 times -- and
    ignoreing the Label. Much nicer.


    You just have to finish up a rendering that does something like

    PreRender(){
    foreach (ListItem X in _Items){
    MySelect.Items.Add(X);
    }
    }



    I think that just about covers Type 3.

    As for the more complicated version -- a Tree that parses its children
    deeper than 1 -- something like a Menu control as I was writting this
    week -- It's so similar -- I just couldn't see it at first.

    The error was two part:
    a) I should have made the attribute:

    [ParseChildren(true,"OUTLOOKBARITEM"),PersistChildren(true),ControlBuilderAt
    tribute(typeof(MyBuilder))]

    on the OutlookBarItem... It's not at all what is happening...

    It should have been

    [ParseChildren(false),PersistChildren(true),
    ControlBuilderAttribute(typeof(MyBuilder))]

    AND

    I should have realized that the OutlookItem -- which is my custom ListItem
    on steroids -- needs to be (duh) a WebControl for it to parse/render.







    Anyway -- the corrected (and working -- although I have not added the JS and
    CSS to make it work) code is attached below -- and it parses correctly as I
    intended...



    I hope that these notes helped rather than confuse you even more...:) Let
    me know -- and I'll try to make another stab at explaining it if I was as
    clear as mud :)

    But buy the book. Was money well spent in my opiou nion. It doesn't answer
    everything (for example I had to figure out how to read nested sets by my
    self) but I don't think I could have without a leg up from the book.

    Plus, As is amply clear by now -- I am neither good with code in the first
    place, nor a good writer -- they are :)



    Very best and good luck,

    Sky

    Ps: one last point -- there is still one last part to work out that i havn't
    figure out: it renders in runtime -- but it's giving me the dreaded gray box
    in the IDE. Something not's instantiated in Design mode? Grrr.








    The corrected code is as follows:
    public class MyBuilder : ControlBuilder {

    public override Type GetChildControlType(string tagName, IDictionary
    attribs) {

    if ((tagName.ToUpper().IndexOf("FOLDER")>-1)||

    (tagName.ToUpper().IndexOf("ITEM")>-1)||

    (tagName.ToUpper().IndexOf("NODE")>-1)){

    return typeof(XOutlookBarItem);


    }

    return null;

    }

    public override void AppendLiteralString(string s) {}

    public override bool AllowWhitespaceLiterals(){return false;}

    }

    [ParseChildren(false),PersistChildren(true)]

    [ ControlBuilderAttribute(typeof(MyBuilder))]

    public class XOutlookBarItem : Control {

    //==========================================================

    //PRIVATE FIELDS

    //==========================================================

    XOutlookBar _ParentMenu =null;

    XOutlookBarItem _ParentNode = null;

    bool _IsFolder=false;

    string _Label = string.Empty;

    string _Url = string.Empty;

    string _ImgUrl = string.Empty;

    string _Target = "_self";

    string _ToolTip = string.Empty;

    //==========================================================

    //PUBLIC PROPERTIES

    //==========================================================

    //----------------------------------------------------------

    [Category(" XAct Appearance")]

    public string ImgUrl {get {return _ImgUrl;}set{_ImgUrl = value;}}

    [Category(" XAct Appearance")]

    public string ImageUrl {get {return _ImgUrl;}set{_ImgUrl = value;}}

    [Category(" XAct Appearance")]

    public bool IsFolder {get {return _IsFolder;}set{_IsFolder = value;}}

    [Category(" XAct Data")]

    public string Label {get {return _Label;}set{_Label = value;}}

    [Category(" XAct Data")]

    public string Url {get {return _Url;}set{_Url = value;}}

    [Category(" XAct Data")]

    public string Target {get {return _Target;}set{_Target = value;}}

    [Category(" XAct Data")]

    public string Title {get {return _ToolTip;}set {_ToolTip =value;}}

    [Category(" XAct Data")]

    public string ToolTip {get {return _ToolTip;}set {_ToolTip =value;}}

    [Browsable(false)]

    public XOutlookBar ParentMenu {get {if (_ParentMenu!=null){return
    _ParentMenu;}else{if (_ParentNode!=null){return
    _ParentNode.ParentMenu;}}return null;}set{_ParentMenu = value;}}

    [Browsable(false)]

    public XOutlookBarItem ParentNode {get {return _ParentNode;}set{_ParentNode
    = value;}}

    //==========================================================

    //CONSTRUCTOR

    //==========================================================

    public XOutlookBarItem():base(){

    this.PreRender += new EventHandler(Page_PreRender);

    }

    //==========================================================

    //LIFECYCLE

    //==========================================================

    protected override void AddParsedSubObject(Object obj) {

    //Only allow Nodes as children:

    if (obj is XOutlookBarItem){

    XOutlookBarItem oNode = (XOutlookBarItem)obj;

    string tCheck = oNode.Label;

    oNode._ParentNode = this;

    oNode._ParentMenu = this.ParentMenu;

    this.Controls.Add(oNode);

    }

    }

    protected void Page_PreRender(object sender, EventArgs e){

    this.Controls.Add(_Render());

    }

    protected override void Render(HtmlTextWriter output) {

    if ((this.Site != null) && (this.Site.DesignMode)){

    this.ChildControlsCreated=false;

    this.EnsureChildControls();

    try{this.OnPreRender(EventArgs.Empty);}catch{}

    }

    base.Render(output);

    }

    //==========================================================

    //PRIVATE METHODS

    //==========================================================

    private WebControl _Render(){

    if (this.IsFolder){return _RenderAsFolder();}else{return _RenderAsItem();}

    }

    private WebControl _RenderAsFolder(){

    Panel oDO = new Panel();

    Panel oDIT = new Panel();oDO.Controls.Add(oDIT);

    Label oLabel = new Label();oDIT.Controls.Add(oLabel);

    oLabel.Text = this.Label;

    Panel oDIB = new Panel();oDO.Controls.Add(oDIB);

    oDO.CssClass = this.ParentMenu.CssClassFolder;

    oDIT.CssClass = this.ParentMenu.CssClassFolderButton;

    oLabel.CssClass = this.ParentMenu.CssClassFolderButtonLabel;

    oDIB.CssClass = this.ParentMenu.CssClassFolderItemArea;

    while (this.Controls.Count>0){

    XOutlookBarItem oChild = (XOutlookBarItem)this.Controls[0];

    //this.Controls.Remove(oChild); //Doesn't look like this is needed...

    oChild.ParentMenu = this.ParentMenu;

    oDIB.Controls.Add(oChild);

    }

    if (this._ToolTip != string.Empty){

    oDIT.ToolTip = _ToolTip;

    oDIT.Style["CURSOR"]="hand";

    }

    if (this.Url!=string.Empty){oDIT.Attributes["Url"] = this.Url;}

    if (this.Target!=string.Empty){oDIT.Attributes["Target"] = this.Target;}

    return oDO;

    }

    private WebControl _RenderAsItem(){

    Panel oDO = new Panel();

    oDO.CssClass = this.ParentMenu.CssClassItem;

    Label oLabel = new Label();oLabel.Text = this.Label;

    oLabel.CssClass = this.ParentMenu.CssClassItemLabel;

    if (this.ParentMenu.ShowItemImages){

    Image oImg = new Image();

    if (this.ParentMenu.ItemImageAlignment == eAlign.Top){

    oDO.Controls.Add(oImg);

    oDO.Controls.Add(new LiteralControl("<br/>"));

    oDO.Controls.Add(oLabel);

    }else if (this.ParentMenu.ItemImageAlignment == eAlign.Right){

    oDO.Controls.Add(oLabel);

    oDO.Controls.Add(oImg);

    }

    else if (this.ParentMenu.ItemImageAlignment == eAlign.Left){

    oDO.Controls.Add(oImg);

    oDO.Controls.Add(oLabel);

    }

    else if (this.ParentMenu.ItemImageAlignment == eAlign.Bottom){

    oDO.Controls.Add(oLabel);

    oDO.Controls.Add(new LiteralControl("<br/>"));

    oDO.Controls.Add(oImg);

    }

    if (this.ImgUrl!=string.Empty){oImg.ImageUrl=this.ImgUrl;}

    oImg.CssClass = this.ParentMenu.CssClassItemImage + " " + "HOVER";

    }else{

    oDO.Controls.Add(oLabel);

    }

    if (this._ToolTip != string.Empty){

    oDO.ToolTip = _ToolTip;

    oDO.Style["CURSOR"]="hand";

    }

    if (this.Url!=string.Empty){oDO.Attributes["Url"] = this.Url;}

    if (this.Target!=string.Empty){oDO.Attributes["Target"] = this.Target;}

    return oDO;

    }



    }


    public enum eAlign{

    Top,

    Right,

    Bottom,

    Left

    }


    /// <summary>

    /// Description résumée de XOutlookBar.

    /// </summary>

    [ParseChildren(ChildrenAsProperties = false)]

    [PersistChildren(true)]

    [ControlBuilderAttribute(typeof(MyBuilder))]

    public class XOutlookBar : WebControl {

    //==========================================================

    //EVENT HANDLING

    //==========================================================

    //==========================================================

    //SUB ELEMENTS

    //==========================================================

    //==========================================================

    //FIELDS

    //==========================================================

    //Javascript:

    private const string _JSClassDefName = "XOutlookBar";

    private const string _JSClassDefFileName = _JSClassDefName + ".js";

    private string _JSClassDefPath = "XAct.Resources.aspx?Assembly="+
    System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Assembly.GetNa
    me().Name + "&" + "Res=";

    static int _JSClassInstanceCounter = 0;

    private string _JSClassInstanceName = string.Empty;

    //----------------------------------------------------------

    //Css:

    private string _CssPath = "";

    private string _CssClassFolder = "XOB_FOLDER";

    private string _CssClassFolderButton = "XOB_FOLDER_BUTTON";

    private string _CssClassFolderButtonLabel = "XOB_FOLDER_BUTTON_LABEL";

    private string _CssClassFolderButtonImage = "XOB_FOLDER_BUTTON_IMAGE";

    private string _CssClassFolderItemArea = "XOB_FOLDER_ITEMAREA";

    private string _CssClassItem = "XOB_ITEM";

    private string _CssClassItemImage = "XOB_ITEM_IMAGE";

    private string _CssClassItemLabel = "XOB_ITEM_LABEL";

    //----------------------------------------------------------

    //Layout:

    private bool _ShowFolderImages = true;

    private bool _ShowItemImages = true;

    private eAlign _FolderImageAlignment = eAlign.Right;

    private eAlign _ItemImageAlignment = eAlign.Top;

    //----------------------------------------------------------

    //Folder Tracking:

    private int _CurrentFolderID = 0;

    //==========================================================

    //PROPERTIES

    //==========================================================

    //----------------------------------------------------------

    [Category(" XAct Behavior")]

    public int CurrentFolderID {get {return _CurrentFolderID;}set
    {_CurrentFolderID = value;}}

    //----------------------------------------------------------

    [Category(" XAct Appearance")]

    public bool ShowFolderImages {get {return _ShowFolderImages;}set
    {_ShowFolderImages = value;}}

    [Category(" XAct Appearance")]

    public bool ShowItemImages {get {return _ShowItemImages;}set
    {_ShowItemImages = value;}}

    [Category(" XAct Appearance")]

    public eAlign FolderImageAlignment {get {return
    _FolderImageAlignment;}set{_FolderImageAlignment = value;}}

    [Category(" XAct Appearance")]

    public eAlign ItemImageAlignment {get {return
    _ItemImageAlignment;}set{_ItemImageAlignment = value;}}

    //----------------------------------------------------------

    [Category(" XAct Appearance - CSS")]

    public string CssPath {get {return _CssPath;}set{_CssPath = value;}}

    [Category(" XAct Appearance - CSS")]

    public string CssClassFolder {get {return
    _CssClassFolder;}set{_CssClassFolder = value;}}

    [Category(" XAct Appearance - CSS")]

    public string CssClassFolderButton {get {return
    _CssClassFolderButton;}set{_CssClassFolderButton = value;}}

    [Category(" XAct Appearance - CSS")]

    public string CssClassFolderButtonLabel {get {return
    _CssClassFolderButtonLabel;}set{_CssClassFolderButtonLabel = value;}}

    [Category(" XAct Appearance - CSS")]

    public string CssClassFolderButtonImage {get {return
    _CssClassFolderButtonImage;}set{_CssClassFolderButtonImage = value;}}

    [Category(" XAct Appearance - CSS")]

    public string CssClassFolderItemArea {get {return
    _CssClassFolderItemArea;}set{_CssClassFolderItemArea = value;}}

    [Category(" XAct Appearance - CSS")]

    public string CssClassItem {get {return _CssClassItem;}set{_CssClassItem =
    value;}}

    [Category(" XAct Appearance - CSS")]

    public string CssClassItemImage {get {return
    _CssClassItemImage;}set{_CssClassItemImage = value;}}

    [Category(" XAct Appearance - CSS")]

    public string CssClassItemLabel {get {return
    _CssClassItemLabel;}set{_CssClassItemLabel = value;}}

    //----------------------------------------------------------

    //[TypeConverter(GetType(System.Drawing.ColorConverter))]




    //==========================================================

    //CONSTRUCTOR

    //==========================================================

    public XOutlookBar():base(HtmlTextWriterTag.Div){

    ResSrvHandler.Install();

    //Init Js:

    _JSClassInstanceName = _JSClassDefName +
    _JSClassInstanceCounter;_JSClassInstanceCounter +=1;

    //Define path to Css Resource:

    if (_CssPath == string.Empty){_CssPath = _JSClassDefPath +
    _JSClassDefName+".css";}


    //Wire up Handlers for Control Events:

    this.PreRender += new System.EventHandler(this.Page_PreRender);

    //Create Controls:

    this.EnsureChildControls();

    }

    //==========================================================

    //LIFECYCLE

    //==========================================================

    protected override void AddParsedSubObject(Object obj) {

    if (obj is XOutlookBarItem){

    //Add to Controls only if of the right type:

    XOutlookBarItem oNode = (XOutlookBarItem)obj;

    //This time I added them directly...no private _List . Seems to work fine.

    this.Controls.Add(oNode);

    }else{

    //Ignore and discard...

    }

    }

    protected override void CreateChildControls(){

    //No Controls to add --- it's all done by AddParsedSubObject

    ChildControlsCreated=true;

    }

    private void Page_PreRender(object sender, EventArgs e){

    foreach (XOutlookBarItem oChild in this.Controls){

    //Wire it up -- the sub items will need a pointer to me to get CSS layout
    info

    oChild.ParentMenu = this;

    }

    _Embed_JS();

    _Embed_CSS();

    }

    protected override void Render(HtmlTextWriter output) {

    if ((this.Site != null) &&
    (this.Site.DesignMode)){try{this.OnPreRender(EventArgs.Empty);}catch{}}

    base.Render(output);


    }

    //==========================================================

    //PRIVATE METHODS

    //==========================================================

    private void _Embed_JS(){

    Tools.EmbedScriptClassDefResource(false,this.Page,_JSClassDefName,
    _JSClassDefFileName, _JSClassDefPath);

    string tJS_Specific =

    string.Format(

    "<script>\n"+

    "//CLASSINIT:BEGIN----------------------------------------------------------
    -\n"+

    _JSClassInstanceName + " = new
    "+_JSClassDefName+"('{0}','{1}','{2}','{3}','{4}','{5}','{6}','{7}','{8}','{
    9}','{10}');\n"+

    "//CLASSINIT:END------------------------------------------------------------
    -\n"+

    "</script>\n",

    this.ClientID,

    _CurrentFolderID,

    string.Empty,

    this._CssClassFolder,

    this._CssClassFolderButton,

    this._CssClassFolderButtonLabel,

    this._CssClassFolderButtonImage,

    this._CssClassFolderItemArea,

    this._CssClassItem,

    this._CssClassItemLabel,

    this._CssClassItemImage

    );

    Page.RegisterStartupScript(_JSClassInstanceName, tJS_Specific);

    }



    private void _Embed_CSS(){

    if (!Page.IsStartupScriptRegistered(_JSClassDefName + "_CSS")){

    string tCSS = string.Format("<link type=\"text/css\" rel=\"StyleSheet\"
    href=\"{0}\"/>\n", _CssPath);

    Page.RegisterStartupScript(_JSClassDefName + "_CSS", tCSS);

    }

    }

    }
     
    Sky, Jul 13, 2004
    #3
  4. Sky

    sica Guest

    Hi Sky!

    This is very usufull information indeed.It help me a lot to understnad
    more about server controls.

    One thing that I'm not sure how to do it is how to control the order
    the sub-controls are render.Let me show you an exemple:

    <cc1:MyControl>
    <option Text="John"/>
    <ITEM Text="Sam"/>
    <option Text="Mary"/>
    <asp:listitem Text="Mary"/>
    <asp:Label Text="Discard me">
    </cc1:MyControl>

    I would always like to render listitem-controls first,then label and
    so on.Do you have an ideea how can I do that?Is it
    ControlBuilderAttribute that govern this if I implemet my own Control
    builder?

    Thanks in advance!

    Regards,
    Sica
     
    sica, Jul 19, 2004
    #4
  5. Sky

    Sky Sigal Guest

    Hi Sica:
    I am really happy you got something from what I wrote -- most of this stuff
    is ...well, I don't yet a firm grip on it all. It's getting better -- but I
    still sometimes start a new control, and I think I understand it -- and then
    I try something simple ...and it doesn't work.

    Anyway...

    I think I understand your question -- but let me point out that in the
    example given I was just trying to show that using a ControlBuilder one
    could make a custom "SELECT" replacement control that could accept several
    types of syntax for OPTION elements without bugging out... Ie, via the
    ControlBuilder one could control the 'meaning' of the parsing -- and that
    whether it were an asp:net element (eg: asp:listitem) which it will
    automatically recognize as being an object of type listitem, or a custom tag
    that it knows nothing of (eg 'option' or 'item', and it would have
    translated it to a LiteralControl if you didn't provide a Builder) you can
    force it to be 'seen/recognized' as being a ListItem, or any other Control
    for that matter....In other words, the example shows that the ControlBuilder
    that I supplied would take each item and make it a ListItem -- no matter if
    I wrote asp:listitem, Option, or Item... The ControlBuilder also shows that
    it can be made to ignore any other tags -- in other words, that asp:label
    will be ignored.

    This doesn't handle sorting though -- in fact once it has been parsed, and
    added (or rejected/ignored) the stuff is no longer an Option, Item, or
    whatever -- that was just some "text/xml" tag -- it is discarded I think
    once it has been parsed, and it is now a Control of type ListItem (atleast
    in terms of the example given).... And I don't know of a way to get back to
    the original WRITTEN tag from that point...it's gone. History.
    So -- sorting by html tag is not possible... I think one could only
    rearrange these elements by their values at this point -- (ie .Text, or
    other property)... with IComparable,etc. ?

    If you do find that it is possible, could you post back your solution?
    Thanks!

    Sky





    "sica" <> wrote in message
    news:...
    > Hi Sky!
    >
    > This is very usufull information indeed.It help me a lot to understnad
    > more about server controls.
    >
    > One thing that I'm not sure how to do it is how to control the order
    > the sub-controls are render.Let me show you an exemple:
    >
    > <cc1:MyControl>
    > <option Text="John"/>
    > <ITEM Text="Sam"/>
    > <option Text="Mary"/>
    > <asp:listitem Text="Mary"/>
    > <asp:Label Text="Discard me">
    > </cc1:MyControl>
    >
    > I would always like to render listitem-controls first,then label and
    > so on.Do you have an ideea how can I do that?Is it
    > ControlBuilderAttribute that govern this if I implemet my own Control
    > builder?
    >
    > Thanks in advance!
    >
    > Regards,
    > Sica
     
    Sky Sigal, Jul 19, 2004
    #5
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Ben
    Replies:
    2
    Views:
    905
  2. Lawrence D'Oliveiro

    Death To Sub-Sub-Sub-Directories!

    Lawrence D'Oliveiro, May 5, 2011, in forum: Java
    Replies:
    92
    Views:
    2,056
    Lawrence D'Oliveiro
    May 20, 2011
  3. Chris Simeone

    Help needed with AddParsedSubObject() and ControlBuilder()

    Chris Simeone, Oct 29, 2004, in forum: ASP .Net Building Controls
    Replies:
    0
    Views:
    136
    Chris Simeone
    Oct 29, 2004
  4. Jonathan Gauthier

    ASP.NET ControlBuilder with ITemplate

    Jonathan Gauthier, Nov 10, 2004, in forum: ASP .Net Building Controls
    Replies:
    0
    Views:
    241
    Jonathan Gauthier
    Nov 10, 2004
  5. mr dropdown

    building a server control using controlBuilder

    mr dropdown, Jan 8, 2006, in forum: ASP .Net Building Controls
    Replies:
    1
    Views:
    143
    mr dropdown
    Jan 8, 2006
Loading...

Share This Page