更好,更强大的类型获取asp.net控件的方式?

时间:2011-07-28 20:37:03

标签: c# asp.net

我有以下功能:

public void rpSearchResults_ItemDataBound(Object Sender, RepeaterItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
    {
        System.Data.Common.DbDataRecord rd = (System.Data.Common.DbDataRecord)e.Item.DataItem;

        Literal litCompanyName = (Literal)e.Item.FindControl("litCompanyName");
        Literal litCompanyLocation = (Literal)e.Item.FindControl("litCompanyLocation");
        Literal litCompanyActivity = (Literal)e.Item.FindControl("litCompanyActivity");
        HiddenField hdnUserID = (HiddenField)e.Item.FindControl("hdnUserID");
        HyperLink lnkEmail = (HyperLink)e.Item.FindControl("lnkEmail");
        HyperLink lnkMicrosite = (HyperLink)e.Item.FindControl("lnkMicrosite");
        Literal litRecommends = (Literal)e.Item.FindControl("litRecommends");

        litCompanyName.Text = rd["CompanyName"].ToString();

        // Construct location info
        litCompanyLocation.Text = "";
        string[] addressParts = {"City","Region","Postcode"};
        bool prior = false;
        foreach (String part in addressParts){
            if (prior) litCompanyLocation.Text = litCompanyLocation.Text + ", ";

            string addressBit = rd[part].ToString();
            if (addressBit == null || addressBit.Trim() == "") prior = false;
            else
            {
                litCompanyLocation.Text = litCompanyLocation.Text + rd[part].ToString();
                prior = true;
            }
        }

        // ... and so on, mapping stuff from the database to fields.
    }
}

它由我的Repeater上的事件触发,用于填充搜索结果列表。找到的所有各种控件都存在于转发器的项模板中。

这一切都有效,但我不想这样做。我讨厌必须通过字符串搜索控件,并且我讨厌必须进行强制转换以使控件进入我可以操作的状态。如果出现任何问题 - 例如,如果我输错了 - 错误只在运行时被选中,并且通常很难跟踪,因为这些函数似乎无声地失败,而不是创建一个明显的错误页面

此代码现已编写,并且可以正常运行。但是在将来我想用一种强类型的不同方式编写它,这样任何错误都会在编译时让它们自己知道。有没有办法做到这一点?

5 个答案:

答案 0 :(得分:2)

您可以将所有控件放入强类型自定义控件(包括ASCX用户控件)中,只需使用FindControl()一次:

CustomControl myControl= (CustomControl) e.Item.FindControl("oMyControl");

myControl.litCompanyName.Text = rd["CompanyName"].ToString();

答案 1 :(得分:2)

注意:根据您在示例中发布的内容,您使用<%#%>复制Repeater类的现有数据绑定功能。句法。我很长时间没有使用ASP.NET数据绑定,所以假设你实际上有充分的理由做很长的事情,这里是你实际问题的答案:

不幸的是,没有任何简单且强类型的方法来实现你想要的,至少不是在“旧”(非MVC - 它有名字吗?)ASP.NET框架。 Repeater控件包含一个Control集合,它只知道其中的每个对象都派生自System.Web.UI.Control。更具体地说,如果您的代码和ItemTemplate不同步,则需要在运行时进行类型转换,这可能会失败。

有一些选项可以让问题减轻痛苦,每个问题都需要权衡取舍:

  1. 保持原样。您的代码有效,您已经知道了难点,并且您已经知道如何避免它们。实用软件开发的首要规则之一是永不破坏工作代码。

  2. 将ItemTemplate中的所有控件包装成强类型的内容,例如ASP.NET用户控件。这非常接近于完成你想要的东西:你只有一次机会搞乱FindControl或类型转换,一旦你处理了你的类型属性。缺点是将数据源绑定到ASCX上控件属性所涉及的额外工作。如果项目模板不经常更改,这可能是您的最佳选择。

  3. 通过检查您的类型转换是否真的有效,您可以获得更好的运行时错误检测。例如:

    Literal litCompanyName = e.Item.FindControl("litCompanyName") as Literal;
    if ( listCompanyName == null )
        LogSomeError("litCompanyName", "Literal");
    

    显然,缺点是输入和维护的代码更多,但是如果你真的发现你的运行时错误被静默吞噬,那么从长远来看这可能会节省你的时间。此外,它还可以让您更好地从错误的类型转换中恢复 由于异常而没有强制整个方法保释。

  4. 避免使用ASP.NET Repeater(或任何其他基于ItemTemplate的控件)。这是对未来产品的更多建议,因为我的第一个建议与@Henk的评论相似 - 使用MVC。 MVC框架的好处很多,强类型模型绑定就是其中之一。它没有的是ASP.NET拥有的现有控件库 - 您需要使用例如部分视图来创建类似转发器的控件。这项工作更多,但从长远来看,很多更容易维护。

答案 2 :(得分:1)

不。这是您需要这样做的方式。您至少在定义中转换为正确的类型,因此您可以使用要键入的对象。

问题是访问hte控件的唯一方法是使用FindControl方法。这就是问题的核心所在 - 如果可以用类型定义的查找替换它会更好。

答案 3 :(得分:1)

不幸的是,没有办法解决。你可以做的最多是创建枚举或常量以传入findcontrol。你需要做的铸造,这对容器控制来说有点烦人。

答案 4 :(得分:1)

你不需要在代码中执行此操作...没关系,但你必须输入字段名两次(一次创建控件,一次为其赋值),这会增加你的错别字的机会。

您可以在转发器的标记中进行分配。 E.g:

<ItemTemplate>
<tr>
<td><%#Container.DataItem("title")%></td>
...

它仍然存在运行时漏洞,但至少您只需要这样输入字段名称。

编辑 - 根据您对3个字段进行组合的评论...这也是在存储过程中完成这项工作的选项......

SELECT
    CAST(address as varchar(100)) +
        CASE WHEN NOT NULLIF(address,'') is null THEN ', ' ELSE '' END +
        CAST (region as varchar(100)) +
        CASE WHEN NOT NULLIF(region,'') is null THEN ', ' ELSE '' END +
        CAST (postcode as varchar(100) as CompanyLocation,
   ...
FROM
    ...