在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上的一个事件触发,并用于填充搜索结果列表。所有被找到的各种控件都出现在重复器的Item Template中。

这些都可以,但是我不喜欢这样做。我讨厌必须按字符串搜索控件,也讨厌必须进行强制类型转换以使控件进入我可以操作的状态。如果出了什么问题——例如,如果我打错了字——这个错误只会在运行时被发现,而且通常很难追踪,因为这些函数似乎是悄无声息地失败的,而不是创建一个明显的大错误页面。

这段代码现在已经写好了,它可以工作了。但是在将来,我想用一种不同的方式来编写它,这种方式是强类型的,这样任何错误都会在编译时发现。有什么办法可以做到吗?

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

CustomControl myControl= (CustomControl) e.Item.FindControl("oMyControl");
myControl.litCompanyName.Text = rd["CompanyName"].ToString();

注意:根据您在示例中发布的内容,您正在使用<%# %>语法复制Repeater类的现有数据绑定函数。我没有用过ASP。. NET数据绑定在很长,很长一段时间内,所以假设你实际上有一个很好的理由去做这件事,这里是你实际问题的答案:

不幸的是,没有任何简单和强类型的方法来完成你想要的,至少不是在"旧"(非mvc——它有一个名字吗?)ASP。净框架。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. js的现有控件库。你需要使用你自己的类似于中继器的控件,例如,分部视图。这是更多的工作,但很多更容易维护从长远来看。

没有。这就是你需要做的。您至少在定义中转换为正确的类型,因此您有一个类型化对象可以使用。

问题是访问这些控件的唯一方法是使用FindControl方法。这就是问题的核心所在——如果可以用一个类型定义的find来代替它,那就好得多了。

不幸的是,没有办法。你最多能做的就是创建枚举或常量来传递findcontrol。你必须这样做,这有点烦人的容器控件

您不需要在代码中这样做…这很好,但是您必须键入两次字段名(一次用于创建控件,一次用于为其赋值),这增加了键入错误的可能性。

你可以在重复器的标记中做赋值。例如:

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

它仍然有一个运行时漏洞,但至少你只需要输入一次字段名。

EDIT—根据您关于合并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
    ...

最新更新