从ascx页面中查找aspx页面上的控件

4

我正在尝试从用户控件(ascx)中查找aspx页面上的标签。显然,Page.FindControl("lablel1")不起作用。我需要在某个地方添加ClientID吗?谢谢。


1
我假设你在问题中的拼写错误(使用了“lablel1”)不是你遇到问题的原因? - Dan Davies Brackett
10个回答

14

我认为你应该停下来,仔细考虑你的设计。你的控件不应该需要了解包含它们的页面 - 你需要从另一个控件中查找页面上的控件这一事实告诉我你应该重新思考这个问题。

根据我所知道的架构,最好的建议是你应该将要查找的控件的引用传递给你的用户控件。这样,你的控件就不必了解自身外部的事物。


2
也许吧,但这不是问题所在。在这种情况下,有一个页面,其中有一个“错误/状态标签”,其值由页面上的任何用户控件设置。它以前是通过索引静态访问的,现在我正在尝试更改为使用某种FindControl。 - halp
+1,在这里传递一个指向错误标签的引用是更好的方法。 - Dan Davies Brackett

3
在控件的直接父级上下文之外使用FindControl()时,需要遍历控件树来查找你的

3
如果层次结构是可预测的,那么像这样的东西应该可以工作。
Me.Owner.FindControl("controlName")

或者...

Me.Owner.Parent.FindControl("controlName")

或者...

Me.Owner.Parent.Parent.FindControl("controlName")

如果无法预测,那么您将需要编写递归(昂贵)函数来查找控件。但是请注意,在这里要小心您的方法,因为如果在大页面上过度使用此类算法,它可能会变得缓慢且难以处理。
以下是一个VB示例,用于向后(从子级到父级)搜索树并查找控件:
Protected Function FindControlByID(ByRef childControl As Control, ByVal ID As String) As Control
    Dim ctrl As Control = childControl.FindControl(ID)
    If Not ctrl Is Nothing Then
      Return ctrl
    Else
      If Not childControl.Parent Is Nothing Then
        Return FindControlByID(childControl.Parent, ID)
      Else
        Return Nothing
      End If
    End If
  End Function

我会这样称呼它:
Dim lbl As Label = FindControlByID(Me.Owner, "label1")

当源代码有多个或两个以上的更新时,层次结构何时可预测? - Rob Allen
从过去的经验来看,当您将控件移入或移出容器(占位符、面板、用户控件等)时,层次结构将发生变化。只要不这样做,那么它就是相当可预测的。当然,另一方面,这是其中一种糟糕的解决方案,如果某些事情确实发生了变化,它会中断,而您可能不记得为什么。但这只是一个理由,如果可以的话,最好避免这样做。 - Steve Wortham
我添加了一个功能,可以在整个控件树中搜索控件。 - Steve Wortham

2
创建一个接口,例如:
public interface IStatusDisplayer
{
   Label StatusLabel { get; }
}

在显示错误/状态标签的任何页面上实现接口。如果您的用户控件需要访问该标签,则可以执行以下操作:

var statusDisplayer = this.Page as IStatusDisplayer;
if (statusDisplayer != null)
{
    statusDisplayer.StatusLabel.Text = "Hello World!";
}

1
Control ct = WebUserControl11.FindControl("DropDownList1");

DropDownList dt = (DropDownList)ct;

TextBox1.Text = dt.SelectedValue.ToString();

1

从用户控件内部

Me.NamingContainer.FindControl("label1")

0

访问意味着从.aspx文件中启用/禁用.ascx中的控件,请尝试此代码,它也是解决方案。

protected void Page_Load(object sender, EventArgs e)
{
    Control ct = PEM.FindControl("btnInsert");
    Button btn = (Button)ct;
    btn.Enabled = false;
}

我不认识 PEM。那是什么? - Rich

0

这很简单,首先您需要访问主页面ContentPlaceHolder:

Dim ContentPlaceHolder1 As ContentPlaceHolder = TryCast(Page.Master.FindControl("ContentPlaceHolder1"), ContentPlaceHolder)

然后,使用ContentPlaceHolder,你现在可以找到aspx页面上控件的ID:

TryCast(ContentPlaceHolder1.FindControl("LiteralOnParentASPXPage"), Literal).Text = "some text" 

0

这是一种蛮力方法,但当控件深度嵌套在控件层次结构中时,它是有效的:

private Control GetTextEditor(ControlCollection controls)
{
    foreach (Control ctrl in controls)
    {
        if (ctrl.ID != null && ctrl.ID == "teMessage")
            return ctrl;
        if (ctrl.Controls.Count > 0)
        {
            Control inner = GetTextEditor(ctrl.Controls);
            if (inner != null)
                return inner;
        }
    }
    return null;
}

0
脑海中浮现出其他几个想法。Page类中有一个“Items”集合,可用于存储值,或者使用Session对象进行类似的思考。另一个是在页面上公开一个公共方法来更新标签。该架构可能存在AJAX问题,因为我不确定回调如何同时更新页面的多个区域,因此这只是一个警告,并不是说我曾经遇到过这个问题。
TheSteve的答案也可以运作,这是我过去必须处理的方式,虽然在控件之间转移时可能会有些棘手。我也同意Andrew的答案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接