How to find a control or page a control is embedded In
I've written a web user control which I want to be able to drop into the markup for either aspx pages or other web user controls.
I need my user开发者_StackOverflow社区 control to be able to easily and efficiently work out if its inside another user control or an aspx page. My initial idea is to do it recursively with checks on the Parent property - continue looking up the nesting hierarchy until I find either a web form or a user control - but I'm not sure this the best way of going about this.
Can you suggest an easier way? Thanks.
Recursively check the type of your Parent
until Parent.GetType()
is either typeof(UserControl)
or type(Page)
private bool IsAncestorTypeOf(Control c, params Type[] typesToCheck)
{
var parent = c.Parent;
if (parent == null) return false;
if (typesToCheck.Contains(parent.GetType())) return true;
return IsAncestorTypeOf(parent, typesToCheck);
}
Or the same without recursion
private bool IsAncestorTypeOf(Control c, params Type[] typesToCheck)
{
var parent = c.Parent;
while (true)
{
if (parent == null) return false;
if (typesToCheck.Contains(parent.GetType())) return true;
parent = parent.Parent;
}
}
Call it like
var isAncestorPageOrUserControl = IsAncestorTypeOf(this, typeof(Page), typeof(UserControl));
or
var isAncestorPage = IsAncestorTypeOf(this, typeof(Page));
var isAncestorUserControl = IsAncestorTypeOf(this, typeof(UserControl));
Generally, components should be unaware of their arbitrary containers, although the containers must know their components (unless it's a strong dependency situation like list items are always in a list type and you can make a strong two way relationship). However it sounds like you are reaching out into the general surroundings. You might find many cases to code for doing this and accidentally miss others.
By making the user control aware of its surroundings and the larger world you may be introducing dependencies that make your control less reusable and harder to maintain.
If something the control needs is outside of itself, you might move toward composition by forcing the developer to provide a reference to the needed thing on a property of your user control. This is the way, for example, that validation controls in ASP.NET do it, to reference an external control to validate by id.
Of course what I specified is practical only some of the time. Is there a specific reason or edge case why you need to make your user control look around itself, or can you get away with providing instructions to the developer about where the control should be used?
This should work:
C#
bool inPage = (this.NamingContainer == this.Page);
VB.NET
Dim inPage as Boolean = Me.NamingContainer is Me.Page
Edit: it seems to be not as simple as i hoped. If the usercontrol resists in a control like a GridViewRow, the NamingControl of it would be the Row and not the Page.
This takes it into account:
C#
public static bool isControlInPageOruserControl(Control uc)
{
bool inPage = uc.NamingContainer is Page;
if (inPage) {
return true;
} else if (uc.NamingContainer is UserControl) {
return false;
} else {
return isControlInPageOruserControl(uc.NamingContainer);
}
}
VB.NET:
Public Shared Function isControlInPageOruserControl(ByVal uc As Control) As Boolean
Dim inPage As Boolean = TypeOf uc.NamingContainer Is Page
If inPage Then
Return True
ElseIf TypeOf uc.NamingContainer Is UserControl Then
Return False
Else
Return isControlInPageOruserControl(uc.NamingContainer)
End If
End Function
精彩评论