none
我该创建用户控件还是自定义控件?回发后数据丢失? RRS feed

  • 问题

  • 我想要创建一个控件,可以如下使用:

    <uc:RatingLabel Rating="5" runat="server" />

    这样就在页面上显示5个星星。

    之所以想这样,是因为我可以在数据控件——如DetailsView——里使用,如下

    <uc:RatingLabel Rating='<%# Eval("rating") %>' runat="server" />

    这样无需后台代码,就能显示个性化的数据了。我目前是用用户控件来做的,代码如下:

    <%@ Control Language="C#" ClassName="RatingLabel" %>
    <script runat="server">
        private float rating;
        private int height = 24;
    
        public decimal Rating
        {
            get { return (decimal) rating; }
            set
            {
                if (value < 0)
                    throw new ArgumentOutOfRangeException("rating不可为负数");
                rating = (float) value;
                label.Attributes["title"] = "Rating " + rating;
    
                label.Controls.Clear();
    
                int roundedValue = (int)Math.Round(rating, 0, MidpointRounding.AwayFromZero);
    
                for (int i = 0; i < roundedValue; i++)
                {
                    HtmlGenericControl img = new HtmlGenericControl();
                    img.TagName = "img";
                    img.Attributes["src"] = ResolveClientUrl("~/Images/star.jpg");
                    img.Attributes["alt"] = "Star";
                    img.Attributes["height"] = height.ToString();
                    label.Controls.Add(img);
                }
            }
        }
    
        public int Height
        {
            get { return height; }
            set { height = value; }
        }
    
    </script>
    <span id="label" runat="server"/>

    这段代码的问题是,当它用在DetailsView的模板里,页面回发后星星就消失了。

    请问面对这种需求,我应该创建用户控件还是自定义控件?为什么?

    为什么用在DetailsView的模板里,页面回发后星星消失?怎么避免这个问题?


    2012年3月17日 3:37

答案

全部回复

  • 原因在于你用UserControl的话没有实现数据绑定接口,导致回传时候无法再次获得数据源。

    两个办法:

    1)Click按钮事件当中再次绑定:

     public partial class UserStar : System.Web.UI.UserControl
        {
            private double rating = 0.0f;
    
            /// <summary>
            /// 绑定Rating
            /// </summary>
            [Bindable(true)]
            public double Rating
            {
                get { return rating; }
                set
                {
                    if (value < 0)
                        throw new ArgumentOutOfRangeException("rating不可为负数");
                    else
                    {
                        rating = value;
                    }
                }
            }
    
            protected override void Render(HtmlTextWriter writer)
            {
                int roundedValue = (int)Math.Round(rating, 0, MidpointRounding.AwayFromZero);
    
                for (int i = 0; i < roundedValue; i++)
                {
                    Response.Write("★");
                }
            }
        }
    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="CSharp.Default" %>
    
    <%@ Register Src="UserStar.ascx" TagName="UserStar" TagPrefix="uc1" %>
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <form id="form1" runat="server">
        <div>
            <asp:Repeater ID="Repeater1" runat="server">
                <HeaderTemplate>
                    <table>
                </HeaderTemplate>
                <ItemTemplate>
                    <tr>
                        <td>
                            <uc1:UserStar ID="UserStar1" runat="server" Rating='<%#Eval("Num") %>' />
                        </td>
                    </tr>
                </ItemTemplate>
                <FooterTemplate>
                    </table>
                </FooterTemplate>
            </asp:Repeater>
        </div>
        </form>
    </body>
    </html>
    namespace CSharp
    {
        public partial class Default : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!IsPostBack)
                {
                    Repeater1.DataSource = new[] 
                    { 
                        new{Num=1.0},
                        new{Num=5.0}
                    };
                    Repeater1.DataBind();
                }
            }
    
            protected void Button1_Click(object sender, EventArgs e)
            {
                Repeater1.DataSource = new[] 
                    { 
                        new{Num=1.0},
                        new{Num=5.0}
                    };
                Repeater1.DataBind();
            }
        }
    }

    2)或者直接使用Rating的AJAX控件(注意不要忘记放上ScriptManager)。

    http://www.asp.net/ajaxLibrary/AjaxControlToolkitSampleSite/Rating/Rating.aspx(设置CurrentRrating作为绑定属性)。


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年3月17日 5:17
  • 我觉得这不是一个好办法。因为asp.net自带的控件如button、label用于数据控件模板里都没有问题,不需要你所谓的Click按钮事件当中再次绑定。
    2012年3月17日 8:50
  • 我觉得这不是一个好办法。因为asp.net自带的控件如button、label用于数据控件模板里都没有问题,不需要你所谓的Click按钮事件当中再次绑定。

    当然不是好办法,但是你的控件只能这样做了。

    还有一个办法,就是你我的代码从IsPostBack中移出来,这样每次回发都自动绑定。

    建议你用AJAX 的Rating控件最好。


       QQ我:讨论(Talk)
    下载MSDN桌面工具(Vista,Win7)
    我的博客园
    慈善点击,点击此处

    2012年3月17日 8:52