Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   ASP .Net Web Controls (http://www.velocityreviews.com/forums/f63-asp-net-web-controls.html)
-   -   Using custom ControlBuilder to parse deep nested sub controls? (http://www.velocityreviews.com/forums/t773762-using-custom-controlbuilder-to-parse-deep-nested-sub-controls.html)

Sky 07-09-2004 10:22 PM

Using custom ControlBuilder to parse deep nested sub controls?
 
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),ControlBuilderAttribu te(typeof(MyBuilder))]
public class OutlookBar(){
.. . .
protected override void AddParsedSubObject(Object obj) {
if (obj is XOutlookBarItem){_Items.Add((XOutlookBarItem)obj); }
}
.. . .
}//Class:End

[ParseChildren(true,"OUTLOOKBARITEM"),PersistChildr en(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(type of(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 07-12-2004 09:35 PM

Re: Using custom ControlBuilder to parse deep nested sub controls?
 
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" <forums@xact-solutions.removethis.com> wrote in message
news:eBKaEMgZEHA.3692@TK2MSFTNGP09.phx.gbl...
> 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),ControlBuilderAttribu te(typeof(MyBuilder))]
> public class OutlookBar(){
> . . .
> protected override void AddParsedSubObject(Object obj) {
> if (obj is XOutlookBarItem){_Items.Add((XOutlookBarItem)obj); }
> }
> . . .
> }//Class:End
>
>

[ParseChildren(true,"OUTLOOKBARITEM"),PersistChildr en(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(type of(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 07-12-2004 11:50 PM

Re: Using custom ControlBuilder to parse deep nested sub controls?
 
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"),PersistChildr en(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.Img Url;}

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().De claringType.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{_CssClassFolderBut tonLabel = value;}}

[Category(" XAct Appearance - CSS")]

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

[Category(" XAct Appearance - CSS")]

public string CssClassFolderItemArea {get {return
_CssClassFolderItemArea;}set{_CssClassFolderItemAr ea = 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.ColorConverte r))]




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

//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(Event Args.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);

}

}

}



sica 07-19-2004 09:02 AM

Re: Using custom ControlBuilder to parse deep nested sub controls?
 
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 07-19-2004 08:22 PM

Re: Using custom ControlBuilder to parse deep nested sub controls?
 
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" <sica74@hotmail.com> wrote in message
news:27826168.0407190102.6feea07e@posting.google.c om...
> 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





All times are GMT. The time now is 07:48 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.