【问题标题】:Load a page's control collection via code通过代码加载页面的控件集合
【发布时间】:2012-04-04 21:19:19
【问题描述】:

我正在尝试编写一个方法来动态加载给定页面的控件集合,以便我可以遍历它并创建驻留在页面上的某些类型的控件的列表。这个想法是,对于从特定页面类继承的任何页面,我想编译一个具有某些属性的可编辑字段列表。这一切都发生在这些页面之外(在允许用户管理这些其他页面的不同页面上)。

我尝试了以下两种情况:

BasePage page = (BasePage)System.Web.Compilation.BuildManager.CreateInstanceFromVirtualPath(string.Format("~/Pages/{0}/Manage.aspx", type.ToString()), typeof(BasePage));

IHttpHandler handler = PageParser.GetCompiledPageInstance(string.Format("~/Pages/{0}/Manage.aspx", type.ToString()), Context.Server.MapPath(string.Format("~/Pages/{0}/Manage.aspx", type.ToString())), HttpContext.Current);
BasePage page = handler as BasePage;

在这两种情况下,页面变量都已启动,但控件集合为空白,可能是因为这两种方法都只加载代码隐藏而不是标记。如何动态加载页面的控件集合?

【问题讨论】:

  • 为什么不能将字段放在用户控件中并从页面 A 和页面 B 访问?您应该无法实例化页面的控件集合,直到它经历了完整的请求生命周期,这与仅实例化该页面的实例不同 - 您可能会发现通过 UserControls 子类化您的字段更容易(您可以使用 Page.LoadControl 动态加载)

标签: c# asp.net


【解决方案1】:

我遇到了完全相同的要求,即需要在运行时从页面 B 评估页面 A 的控件。

在页面的整个生命周期中运行该页面还需要一个额外的步骤。我们只需要调用 Page.ProcessRequest() 方法。 Page.ProcessRequest Method (MSDN)。该方法对 Intellisense 隐藏。

之后,您将能够访问页面中的控件:

Page page = (Page)BuildManager.CreateInstanceFromVirtualPath("~/MyPage.aspx", typeof(Page));
page.ProcessRequest(HttpContext.Current);

如果您的页面有母版页,您需要深入了解母版页的占位符。

请务必注意微软的言论:

“你不应该调用这个方法。”

“此 API 支持 .NET Framework 基础架构,不打算直接从您的代码中使用。

我还不知道这样做是否有任何不利影响。


编辑:在一个页面内执行一个页面会导致无数的问题,所以我选择了一个稍微不同的方向。

使用HTML Agility Pack,我们可以很容易地加载*.aspx 文件并递归遍历其节点。如果我们想查找一个页面上所有的asp按钮,例如:

private static void FindAllButtonControls(HtmlNodeCollection htmlNodeCollection, List<HtmlNode> controlNodes)
{
    foreach (HtmlNode childNode in htmlNodeCollection)
    {
        if (childNode.Name.Equals("asp:button"))
        {
            controlNodes.Add(childNode);
        }
        else
        {
            FindAllButtonControls(childNode.ChildNodes, controlNodes);
        }
    }
}

public static List<HtmlNode> FindButtonControlsAtVirtualPath(String path)
{
    HtmlAgilityPack.HtmlDocument aspx = new HtmlAgilityPack.HtmlDocument();

    aspx.OptionFixNestedTags = true;
    aspx.Load(HttpContext.Current.Server.MapPath(path));

    List<HtmlNode> controlNodes = new List<HtmlNode>();
    FindAllButtonControls(aspx.DocumentNode.ChildNodes, controlNodes);

    return controlNodes;
}

【讨论】:

    【解决方案2】:

    我不会搞乱页面生命周期。让 ASP.NET 自己管理控件层次结构,并使用一些递归逻辑来检查页面上的控件:

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!Page.IsPostBack)
        {
            FindPanelControls(Page);
        }
    }
    
    private void FindPanelControls(Control ctrl)
    {
        if (ctrl.HasControls())
        {
            foreach (var childCtrl in ctrl.Controls.OfType<WebControl>())
            {
                //check for certain attributes
                if (childCtrl is Panel)
                    Response.Write(childCtrl.ID);
    
                //recursively call the function for this control
                FindPanelControls(childCtrl);
            }
        }
    }
    

    【讨论】:

    • 问题是我坐在页面 B 上,我只需要获取页面 A 的控件集合的一个实例,这样我就可以看到它包含哪些字段。这样我就可以在数据库中存储有关所述字段的信息,而不必保留另一个只定义页面上的字段的表(这是多余的,因为它已经在标记中)。
    • 为什么需要从页面B访问页面A?为什么不能从页面A 访问页面A
    • 因为我需要管理字段列表,而我的选项是 a) 使用“reelections 类型”方法获取另一个页面上的字段列表,我可以使用该列表加载到下拉列表中用于用户选择或 b) 在数据库中创建一个包含我们要让用户管理的所有字段的表。选项 b 不好,因为当我们创建新页面或修改现有页面时,我们不仅必须向标记添加字段(按照通常的 Web 开发),而且我们还需要将所述字段添加到数据库中,以便可以在页面外部对其进行管理.这是为了创建一个规则引擎来确定是否需要某个字段。
    【解决方案3】:

    你把它弄得太复杂了;只需递归循环遍历 Page.Controls 集合并检查您感兴趣的控件类型。看看这些较早的问题:

    ASP.Net / C#, Loop through certain controls on a page?

    Loop through all controls on asp.net webpage

    【讨论】:

    • 问题是我需要遍历未加载页面上的控件。我在页面 B。我需要页面 A 的控件集合。
    • 在加载时在页面 A 中循环它们并将您的值存储在 Session 中?
    • 对每个页面使用数据库表条目。例如:在页面A加载,更新该页面的记录 - bool加载等,并为每种类型的控件(相关表)提供字段
    • 实际上,在阅读您对 James 的回复时,我想到了使用 ASP.NET 工作流的想法...
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-30
    • 1970-01-01
    • 2013-01-21
    • 2012-03-06
    • 1970-01-01
    相关资源
    最近更新 更多