Joh*_*n K 7 asp.net user-controls webforms
我想拦截我自己的用户控件的整个子树中的每个控件的解析.
目前我已经在我的用户控件中重写了受保护的方法Control.AddParsedSubObject.它仅限于在声明性语法中截取对直接子控件的解析,因为每个控件都有自己的AddParsedSubObject方法来进一步解析自己的子控件.
从用户控件我无法进入孩子的孩子来拦截那些解析呼叫.
在我的用户控件的以下声明性示例中,我可以从User Control的AddParsedSubObject覆盖内部访问tv对象.
<asp:TreeView runat="server" id="tv" />
Run Code Online (Sandbox Code Playgroud)
但是,我无法访问以下示例中的tv对象(或第一个Panel的其他子对象),因为该解析由Panel或其子代进行处理.
<asp:Panel runat="server">
<asp:TreeView runat="server" id="tv" />
<asp:Panel runat="server">
<asp:TextBox runat="server" />
</asp:Panel>
</asp:Panel>
Run Code Online (Sandbox Code Playgroud)
我在用户控件中的代码隐藏看起来像这样
// User control interception of its parsed children
protected override void AddParsedSubObject(object obj) {
// Do some custom work with the control object.
if (obj is Control && ((Control)obj).ID == "tv") {
TreeView tv = (TreeView)obj;
DoSomethingWithParsedObject(tv);
}
// Let ASP.NET continue and put the control in the page hierarchy
base.AddParsedSubObject(obj);
}
Run Code Online (Sandbox Code Playgroud)
寻找有关如何拦截用户控件的整个子树中的每个控件的解析的想法.例如,我想在每个解析步骤中写出自定义信息.
如果您使用.Net 4.5,有一个很好的方法来实现它。Asp.Net 使用 ControlBuilder 从 aspx 布局构建临时 cs 文件。在.Net 4.5之前,您只能通过反射并切换ControlBuilder类中的一些内部静态变量来拦截它。
但在 .Net 4.5 中,他们添加了新类ControlBuilderInterceptor。然后你可以写这样的代码:
namespace TestInterceptApp
{
public class BuilderInterceptor : ControlBuilderInterceptor
{
public override void OnProcessGeneratedCode(ControlBuilder controlBuilder, CodeCompileUnit codeCompileUnit, CodeTypeDeclaration baseType,
CodeTypeDeclaration derivedType, CodeMemberMethod buildMethod,
CodeMemberMethod dataBindingMethod, IDictionary additionalState)
{
base.OnProcessGeneratedCode(controlBuilder, codeCompileUnit, baseType, derivedType, buildMethod, dataBindingMethod, additionalState);
buildMethod.Statements.Insert(
buildMethod.Statements.Count - 1,
new CodeSnippetStatement("TestInterceptApp.ControlInterceptor.Intercept(@__ctrl);"));
}
}
}
Run Code Online (Sandbox Code Playgroud)
然后你需要修改web.config中的编译部分以将此类注册到Asp.Net:
<system.web>
<compilation debug="true" targetFramework="4.5" controlBuilderInterceptorType="TestInterceptApp.BuilderInterceptor"/>
</system.web>
Run Code Online (Sandbox Code Playgroud)
然后你可以像这样编写这个拦截器类:
namespace TestInterceptApp
{
public static class ControlInterceptor
{
public static void Intercept(TreeView control)
{
// Do some custom work with the control object.
if (control.ID == "tv")
{
control.Nodes.Add(new TreeNode("Test"));
}
}
public static void Intercept(object obj)
{
// just ignore all others controls
}
}
}
Run Code Online (Sandbox Code Playgroud)
基本上当ControlBuilder创建新的cs文件时,它会插入这一行
"TestInterceptApp.ControlInterceptor.Intercept(@__ctrl);"
Run Code Online (Sandbox Code Playgroud)
到每个控制生成块的末尾。您可以使用对象参数在 ControlInterceptor 类中定义一个方法,也可以使用特定参数进行一些所需的重载。并加上一个带有对象参数的基本方法。当CLR执行它时,如果控件是TreeView,那么它会将其发送到正确的方法。对于所有其他控件,如 Literal、Button、HtmlHead、Page 等,CLR 将使用带有对象签名的方法。
我的示例将仅向当前应用程序中 ID=“tv”的每个 TreeView 添加新的 TestNode。ControlBuilder生成的代码是这样的:
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
private global::System.Web.UI.WebControls.TreeView @__BuildControltv() {
global::System.Web.UI.WebControls.TreeView @__ctrl;
#line 32 "c:\users\someuser\documents\visual studio 11\Projects\TestInterceptApp\TestInterceptApp\Default.aspx"
@__ctrl = new global::System.Web.UI.WebControls.TreeView();
#line default
#line hidden
this.tv = @__ctrl;
@__ctrl.TemplateControl = this;
@__ctrl.ApplyStyleSheetSkin(this);
#line 32 "c:\users\someuser\documents\visual studio 11\Projects\TestInterceptApp\TestInterceptApp\Default.aspx"
@__ctrl.ID = "tv";
#line default
#line hidden
#line 32 "c:\users\someuser\documents\visual studio 11\Projects\TestInterceptApp\TestInterceptApp\Default.aspx"
this.@__BuildControl__control3(@__ctrl.Nodes);
#line default
#line hidden
// here is that line that we added via ControlBuilderInterceptor
TestInterceptApp.ControlInterceptor.Intercept(@__ctrl);
this.@__PageInspector_SetTraceData(new object[] {
@__ctrl,
null,
1838,
368,
false});
return @__ctrl;
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
364 次 |
| 最近记录: |