【Asp.net之旅】-数据绑定控件之DataList

【Asp.net之旅】--数据绑定控件之DataList
       上篇博客讨论了Repeater控件的基本用法,它是最基本的数据绑定控件,只提供了数据绑定的功能,熟练运用Repeater控件后,其它类似的数据绑定控件就很简单了。接着我们上篇博客的内容继续,今天来讨论下DataList的基本使用方法。


一、绑定控件之DataList


       该控件可以以自定义的格式显示各种数据源的字段,其显示数据的格式在创建的模板中定义,可以为项、交替项、选定项和编辑项创建模板。该控件也可以使用标题、脚注和分隔符模板自定义整体外观,还可以一行显示多个数据行。虽然DataList控件拥有很大的灵活性,但其本身不支持数据分页,编程者需要通过自己编写方法完成分页的功能。仅用于数据的显示,不支持编辑、插入、删除。
       优点:自定义格式显示数据、比较灵活。
       缺点:不支持分页,编辑插入。


   1、DataList简介


        上文说到DataList控件不仅能够灵活的显示数据,而且还支持编辑、插入、删除操作。想要显示数据基本的模板是必不可少的,相同的该控件也为开发人员提供了基本的模板使用。另外DataList不但提供了基本的ItemCommand事件,而且还封装了删除、取消、编辑、更新事件。通过将数据绑定到EditItemTemplate模板中能够容易的进入编辑状态,具体方法将会在下文中讲到。

【Asp.net之旅】-数据绑定控件之DataList

        对于基本的模板和事件的使用方法上篇文章已经讨论,在此将不会深入的讨论。


二、控件使用技巧


 1、基本操作--增删改


      下面的代码示例使用Asp.net实现,能够对数据进行增加、删除、修改。DataList控件封装了基本的删除和修改模板,但没有继承插入功能,示例中的插入使用的是Asp.net的Literal控件来实现的,具体实现方法如下。
      删除页面:

【Asp.net之旅】-数据绑定控件之DataList


    添加页面:

【Asp.net之旅】-数据绑定控件之DataList

    编辑页面:

【Asp.net之旅】-数据绑定控件之DataList


      前台代码:和Repeater控件基本用法相同,不同的是新增加了编辑模板,在编辑模板中绑定了数据,在进行编辑操作时只要跳转到编辑模板即可。代码中在基本模板ItemTemplate中添加了Literal控件,当点击添加按钮时再后台动态的添加新行,并在新行中添加数据控件。具体后台代码如下。

<div>
    <asp:DataList ID="DataList1" runat="server" OnItemCommand="DataList1_ItemCommand" OnCancelCommand="DataList1_CancelCommand" OnUpdateCommand="DataList1_UpdateCommand" OnEditCommand="DataList1_EditCommand" OnDeleteCommand="DataList1_DeleteCommand">
        <HeaderTemplate>
            <table border="1px" cellpadding="1px" cellspacing="5px" style="text-align:center;border-collapse:collapse;border-color:red;">
                <tr style="background-color:yellow;">    
                    <th>ID</th>
                    <th>内容</th>
                    <th>编辑</th>
                </tr>
        </HeaderTemplate>
        <ItemTemplate>
            <tr onmouseover="backcolor=this.style.backgroundColor;this.style.backgroundColor='#6699ff'" onmouseout="this.style.backgroundColor=backcolor">
                <td><%# Eval("id") %></td>
                <td><%# Eval("name") %></td>
                <td>
                    <asp:LinkButton ID="lbtDelete" runat="server" CommandName="Delete" CommandArgument='<%#Eval("id") %>'>删除</asp:LinkButton>
                    <asp:LinkButton ID="lbtEdit" runat="server" CommandName="Edit" CommandArgument='<%#Eval("name") %>'>编辑</asp:LinkButton>
                    <asp:LinkButton ID="lbtAdd" runat="server" CommandName="Add">添加</asp:LinkButton>
                </td>
            </tr>
            <!--添加新行时动态添加文本框-->
            <asp:Literal ID="litAdd" runat="server"></asp:Literal>              
        </ItemTemplate>
            
        <EditItemTemplate>
            <tr>
                <td>
                    <asp:TextBox ID="id" runat="server" Text='<%#Eval("id") %>'></asp:TextBox>
                </td>
                <td>
                    <asp:TextBox ID="name" runat="server" Text='<%#Eval("name") %>'></asp:TextBox>
                </td>
                <td>
                    <asp:LinkButton ID="lbtCancel" runat="server" Text="取消" CommandName="Cancel"></asp:LinkButton>
                    <asp:LinkButton ID="lbtUpdate" runat="server" Text="更新" CommandName="Update"  CommandArgument='<%#Eval("id") %>'></asp:LinkButton>
                </td>
            </tr>
                
        </EditItemTemplate>
        <FooterTemplate>
            </table>
        </FooterTemplate>
    </asp:DataList>

    <!--分页控件-->
    <div class="pageBar">
        <asp:Literal ID="lit" runat="server"></asp:Literal>
    </div>
</div>

       后台代码:添加新行的操作是在ItemCommand事件中指定的,将新行的代码添加到Literal控件上实现了添加新行,并为新行指定控件。另外的基本编辑命令是在单独的事件中编写的,因为DataList为开发人员提供了基本的操作事件,如果想要进入某一个状态只需要将状态的ItemIndex值。

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        string strName = string.Empty;  //声明添加的内容

        try
        {
            //获取需要添加的内容
            strName = Request.QueryString["name"].ToString();
        }
        catch
        {

        }

        //判断如果要添加的内容不为空将会进行添加操作
        if (strName!=string.Empty)
        {
            this.Insert(strName);
        }

        //**********************************************************************
        //分页效果实现
        PagedDataSource pds = new PagedDataSource(); //声明分页类
        //设置分页属性
        pds.AllowPaging = true;
        pds.PageSize = 3;
        pds.DataSource = this.GetDT().DefaultView;
        pds.CurrentPageIndex = pageIndex - 1;
        //**********************************************************************

        //绑定分页数据源
        this.DataList1.DataSource = pds;
        this.DataList1.DataBind();
    }
}

/// <summary>
/// 添加新的数据行内容
/// </summary>
/// <param name="strName">获取要插入的内容</param>
private void Insert(string strName) {
    //向数据库中插入新内容
    using (SqlConnection con = this.GetSqlCon())
    {
        con.Open(); //打开数据库连接
        //设置命令对象
        SqlCommand sqlcom = new SqlCommand();
        sqlcom.Connection = con;
        sqlcom.CommandText = "insert match values(@name)";
        //添加参数
        sqlcom.Parameters.Add(new SqlParameter("@name", strName));
        //执行插入
        sqlcom.ExecuteNonQuery();
    }
}

/// <summary>
/// 获取绑定的数据源
/// </summary>
/// <returns>DataTable,从match表中获取的内容</returns>
private DataTable GetDT()
{
    DataTable dt = new DataTable(); //声明数据库表
    //获取数据源
    using (SqlConnection con = this.GetSqlCon())
    {
        con.Open();
        //声明数据源命令
        SqlCommand sqlCom = new SqlCommand();
        sqlCom.CommandText = "select * from match";
        sqlCom.Connection = con;
        SqlDataAdapter sqlDa = new SqlDataAdapter(sqlCom);
        SqlCommandBuilder sqlCb = new SqlCommandBuilder(sqlDa);
        sqlDa.Fill(dt);
    }

    return dt;
}

/// <summary>
/// 声明数据库链接对象
/// </summary>
/// <returns>SqlConnection,返回数据库连接对象</returns>
private SqlConnection GetSqlCon()
{
    SqlConnection sqlCon = new SqlConnection("server=.;database=myblog;uid=sa;pwd=1");
    return sqlCon;
}

/// <summary>
/// 编辑命令事件
/// </summary>
/// <param name="source"></param>
/// <param name="e"></param>
protected void DataList1_EditCommand(object source, DataListCommandEventArgs e)
{
    this.DataList1.EditItemIndex = e.Item.ItemIndex;    //设置编辑的索引行
    //重新绑定数据源
    this.DataList1.DataSource = this.GetDT();
    this.DataList1.DataBind();
}

/// <summary>
/// 删除命令事件
/// </summary>
/// <param name="source"></param>
/// <param name="e"></param>
protected void DataList1_DeleteCommand(object source, DataListCommandEventArgs e)
{
    if (e.CommandName == "Delete")
    {
        string id = e.CommandArgument.ToString();   //获取要删除行的id号
        //执行删除命令
        using (SqlConnection con = this.GetSqlCon())
        {
            con.Open();

            SqlCommand sqlcom = new SqlCommand();
            sqlcom.Connection = con;
            sqlcom.CommandText = "delete from match where id=@id";

            sqlcom.Parameters.Add(new SqlParameter("@id", id));
            sqlcom.ExecuteNonQuery();
        }

        //重新绑定数据
        this.DataList1.DataSource = this.GetDT();
        this.DataList1.DataBind();
    }
}

/// <summary>
/// 取消更新事件
/// </summary>
/// <param name="source"></param>
/// <param name="e"></param>
protected void DataList1_CancelCommand(object source, DataListCommandEventArgs e)
{
    if (e.CommandName == "Cancel")
    {
        this.DataList1.EditItemIndex = -1;
        //重新绑定数据
        this.DataList1.DataSource = this.GetDT();
        this.DataList1.DataBind();
    }
}

/// <summary>
/// 更新按钮事件
/// </summary>
/// <param name="source"></param>
/// <param name="e"></param>
protected void DataList1_UpdateCommand(object source, DataListCommandEventArgs e)
{
    //判断如果是更新命令的话,将会执行更新命令
    if (e.CommandName == "Update")
    {
        int intId = int.Parse(e.CommandArgument.ToString()); //获取更新行的索引号
        string strname = ((TextBox)e.Item.FindControl("name")).Text;    //获取更新的内容

        //更新数据库中的值
        using (SqlConnection sqlcon = this.GetSqlCon())
        {
            sqlcon.Open();
            SqlCommand sqlcom = new SqlCommand();
            sqlcom.CommandText = "update match set name=@name where id=@id";
            sqlcom.Connection = sqlcon;

            SqlParameter[] sqlParam = new SqlParameter[] { new SqlParameter("@name", strname), new SqlParameter("@id", intId) };
            sqlcom.Parameters.AddRange(sqlParam);

            sqlcom.ExecuteNonQuery();

        }
        //更新完成后跳转页面
        this.DataList1.EditItemIndex = -1;
        //重新绑定数据
        this.DataList1.DataSource = this.GetDT();
        this.DataList1.DataBind();

    }
}

/// <summary>
/// 事件回发命令
/// </summary>
/// <param name="source"></param>
/// <param name="e"></param>
protected void DataList1_ItemCommand(object source, DataListCommandEventArgs e)
{
    //判断如果命令名称为Add,将会添加新行
    if (e.CommandName == "Add")
    {
        Literal lit = (Literal)e.Item.FindControl("litAdd");    //获取页面的对象

        //向页面中添加新行标签
        StringBuilder strAdd = new StringBuilder("<tr><td><input type=\"text\" id=\"45\"></td><td><input type=\"text\" id='name' onchange='InputKey()'></td>");
        strAdd.Append("<td><a href='Default.aspx' id='CancelInsert'>取消</a>");
        strAdd.Append("<a id='ok'>确认</a>");
        strAdd.Append("</td></tr>");

        //将新行标签日俺家到html中
        lit.Text = strAdd.ToString();
    }
}


 2、分页实现


      分页的实现效果和Repeater控件分页类似。在前台页面中添加Literal控件,并在后台使用PagedataSource类将数据进行分页。
      前台代码:在页面的最后添加了一个分页的div标记,并在div中添加了Literal控件,控件中标签的链接地址是在后台动态指定的。

<head runat="server">
    <title></title>
    <script src="Scripts/jquery-1.7.1.js"></script>
    
    <script type="text/javascript" language="javascript">

        $(function () {
            $("#ok").css("text-decoration", "underline").css("color", "blue");  
            $("#CancelInsert").attr("href","Default.aspx");
        });

        function InputKey() {
            var vartext = document.getElementById("name").value;
            $("#ok").attr("href","Default.aspx?name=" + vartext);       
        }      
    </script>

    <style type="text/css">
        .pageBar {
            margin-top:50px;
        }
        .pageBar a{
            margin-top:50px;
            margin-left:20px;
            border-collapse:collapse;
            border:solid 1px black;
            background-color:#fbf9f9;
            padding:4px 4px 4px 4px;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
        
        <div>
            <!--分页控件-->
            <div class="pageBar">
                <asp:Literal ID="lit" runat="server"></asp:Literal>
            </div>
        </div>
    </form>
</body>
</html>


      后台代码:每次向后台请求数据都会重新为<a>标签指定链接页面的地址,这样能够使得PagedataSource能够链接到想要的页面。

protected void Page_Load(object sender, EventArgs e)
{
    if (!Page.IsPostBack)
    {
        int pageIndex = 1;  //声明页索引
        try
        {
            //获取要跳转页的索引号    
            pageIndex = int.Parse(Request.QueryString["Page"].ToString());
            //如果是第零页,将会赋值为第一页
            if (pageIndex<0)
            {
                pageIndex = 1;
            }
        }
        catch
        {
            //默认显示的是第一页
            pageIndex = 1;
        }

        //判断如果要添加的内容不为空将会进行添加操作
        if (strName!=string.Empty)
        {
            this.Insert(strName);
        }

        //**********************************************************************
        //分页效果实现
        PagedDataSource pds = new PagedDataSource(); //声明分页类
        //设置分页属性
        pds.AllowPaging = true;
        pds.PageSize = 3;
        pds.DataSource = this.GetDT().DefaultView;
        pds.CurrentPageIndex = pageIndex - 1;
        //**********************************************************************

        //绑定分页数据源
        this.DataList1.DataSource = pds;
        this.DataList1.DataBind();
        //添加分页标签
        this.lit.Text = this.GetPageBar(pds);
    }
}
/// <summary>
/// 添加并设置分页命令
/// </summary>
/// <param name="pds">分页数据源</param>
/// <returns>包含分页连接的a标签</returns>
private string GetPageBar(PagedDataSource pds) {
    string Page = string.Empty;
    int intCurrent = pds.CurrentPageIndex + 1;

    //设置首页链接地址
    if (intCurrent==1)
    {
        Page += "<a href=\"javascript:void(0)\">首页</a>";// 转义字符:\"为双引号
    }
    else
    {
        Page += "<a href=\"" + Request.CurrentExecutionFilePath + "?Page=1\">首页</a>";
    }

    //设置上一页链接地址
    if ((intCurrent-1)<1)
    {
        Page += "<a href=\"javascript:void(0)\">上一页</a>";
    }
    else
    {
        Page += "<a href=\"" + Request.CurrentExecutionFilePath + "?Page=" + (intCurrent - 1) + "\">上一页</a>";
    }

    //设置下一页链接地址
    if ((intCurrent+1)>pds.PageCount)
    {
        Page +="<a href=\"javascript:void(0)\">下一页</a>";
    }
    else
    {
            Page +="<a href=\""+Request.CurrentExecutionFilePath +"?Page="+(intCurrent+1)+"\">下一页</a>";   
    }

    //设置末页的链接
    if (intCurrent==pds.PageCount)
	{
        Page += "<a href=\"javascript:void(0)\">末页</a>";
    }
    else
    {
        Page += "<a href=\"" + Request.CurrentExecutionFilePath + "?Page=" + pds.PageCount + "\">末页</a>";
    }

    return Page;    //返回也标签
}

具体代码示例,请下载:DataList示例。


三、对比升华


       结合前篇文章来对比下这两个数据绑定控件,对于Repeater控件它是微软开发的最基础的绑定控件只为开发人员提供了基本的事件流和基本的模板,各个子项完全可以由开发人员自己编写,而且不会生成冗余代码,唯一美中不足的是微软没封装向分页、编辑之类的功能,想要实现该功能必须自己编写了。

       相较Repeater控件,DataList控件不仅在Repeater基础上封装了编辑、删除、更新、取消之类的事件,而且还添加了Selectedtemplate模板,能够在后台代码中编写被选中行的显示效果,而且应用灵活,美中不足的是它也没有封装分页、插入的功能,只能由开发人员自己编写了,另外采用可视化窗口设计DataList样式后会生成冗余的代码,不便于阅读。

       总之在使用时它们两个各有利弊,如果只想绑定和显示数据那Repeater控件当然是我们的首选,当然如果有编辑、删除之类的操作,并想提前设计绑定样式的话不妨使用DataList。


结语

       

        对比两个控件它们都有优缺点,那是不是就没有较完美一些的绑定控件了呢?当然不是,.NET封装了多个数据绑定控件,上面的两种是在编程中经常用到的,真正功能齐全的是ListView控件,它的使用我们将会在下篇文章中着重讨论。