views:

726

answers:

4

I realize that a whole lot of code cannot fit here, but I am asking for general direction or pointer.

I have .NET user controls nested six deep for an interactive gadget with (outer to inner) of : wrapper, tabs, panels, lists, rows, items.

I am trying to get a reference to an ancestor control from a nested control.

Specifically, I have this code in the code behind of a embedded "great great grand child" control. It works, but it is very ugly:

MyTab _myTab = this.Parent.Parent.Parent.Parent.FindControl(thisTab) as MyTab;

which equals {ASP.controls_appname_widget_mywidget_mytab_ascx} and is correct.

I realize that I can do something like Page.FindControl("MyWrapper:MyPanel:etc.....) but that is not recommended either, since structure or IDs can change....

Is there a decent alternative?

A: 

Howdy, you could use the WebControl selector which is actually an independant project (license == LGPL) but still part of the main Ra-Ajax download...

Check out both the code and sample use here...

Then you could just search from the Page object and it'll recursively look for a control matching your (whatever) criteria in the delegate...

Thomas Hansen
+2  A: 

Remember that components are best made ignorant. You never want any control to have any knowledge of anything above itself in the hierarchy and to have interface-only knowledge of controls below itself in the hierarchy. This architectural approach will save you much pain and suffering in the long run and will avoid situations like you are in now.

As for fixing the current problem the best way to fix it is to create a MyTab member in your control that is settable by parent controls. This is not a perfect solution as your control is not totally ignorant of others but at least you will no longer have to know how to get the MyTab reference - it will be provided to you.

So I would create a property called something like ParentTab and set this property equal to the MyTab reference somewhere in the page or inside a control that does and should have visibility to both MyTab and your control.

Andrew Hare
A: 

I think it really depends on your usage of the controls. If the control only serves one business need and is just used on one page to satisfy a use case, then there is no need to go crazy with interfaces and properties. I don't see anything wrong with the parent.parent.parent.etc idea; used it many times myself. I would wrap it up in a property though so that whenever you need it you can call this.MyGreatGreatGrandFatherProperty. It will be more readable and if your hierarchy depth changes you only have one place to fix.

Now if it is a generic component that you don't control the use of, or will be needed in many use cases, then you need to add properties for the parent to tell you who they are to keep de-coupled.

DancesWithBamboo
A: 

@Andrew, not to hijack my own thread but just to clarify and discuss a design approach. You have said "You never want any control to have any knowledge of anything above itself in the hierarchy..." That is a great design stategy for obvious reasons. But what about the case of a wrapper container with some sort of centralized management built in? For example, in .NET, a ScriptManager control in a nested Master Page. You would want a script manager created once only, and you would want it to be available to various controls in the application. For example, any UpdatePanel in any embedded control in the app would want to know about the existence of that ScriptManager. Is this a wrong approach?

My design is similar - the outermost wrapper container manages object persistence, and each control can save it's state to that Manager. I am thinking now that wrapper delegates are the best design for this. Because I don't like the Parent.Parent. etc nor traversing the control IDs just to make a reference. Any comments welcome.

Ash Machine