• Repeater排序的三种实现方式(附在线Demo)


    Repeater控件是较为干净的服务端数据控件,它不像GridView已经包含了分页和排序功能,这两个小功能都要咱们自己去实现。由于分页的功能很容易实现,我也没什么好讲的;下文中我提供了三种排序方式,除了传统方式以外,另外两种都较为简便灵活。

    在线Demo:

    1. Demo - Repeater 传统排序
    2. Demo - Repeater 反射排序方式
    3. Demo - Repeater Linq 扩展方法排序方式

    本篇文章已经同步至我的个人博客站点:积累吧 | Repeater排序的三种实现方式(附在线Demo),这里有更好的博客视觉体验。

    1. 数据准备

    数据库Test,表名Books,下图是表结构,在Books表中我准备了100条测试数据。

    image

    在页面上除了Id以外其它字段都会被显示。Repeater的数据源由NHibernate下的Repository模式提供,由于只有一个表而且给出了表图,Book.cs和Book.hbm.xml代码我不会贴出来。

    在将要进行的几种Demo中都包含下面4个代码片段,如果大家对这4个片段不感兴趣,可以直接略过去,直接跳转到:

    片段1:获取数据源,缓存

    #region Properties
    
    /// <summary>
    /// Book仓储器
    /// </summary>
    private IBookRepository BookRepository
    {
        get { return new BookRepository(); }
    }
    
    /// <summary>
    /// Cache缓存数据源
    /// </summary>
    private IList<Book> DataSource
    {
        get { return Cache["_data"] as IList<Book>; }
        set
        {
            if (Cache["_data"] == null)
            {
                Cache["_data"] = value;
            }
        }
    }
    
    #endregion
    

    片段2:绑定Repeater

    #region Private Methods
    
    /// <summary>
    /// 绑定Repeater
    /// </summary>
    private void BindRepeater()
    {
        if (DataSource == null)
        {
            IList<Book> books = BookRepository.GetAll().ToList();
            DataSource = books;
        }
    
        // 首次加载时绑定数据源
        if(ViewState["SortOrder"] == null)
        {
            this.Repeater1.DataSource = DataSource;
            this.Repeater1.DataBind();
        }
    }
    
    #endregion
    
    

    片段3:排序设置

    /// <summary>
    /// 设置排序字段、排序方式、排序文本
    /// </summary>
    private void SetSorting(RepeaterCommandEventArgs e)
    {
        var sort = (LinkButton)e.Item.FindControl(e.CommandName.Trim());
        if (e.Item.ItemType == ListItemType.Header)
        {
            string sortText = string.Empty;
    
            // 存储排序字段、排序方式、排序文本
            if (ViewState["SortOrder"] == null || ViewState["SortBy"].ToString() != e.CommandName)
            {
                ViewState["SortOrder"] = "ASC";
                ViewState["SortBy"] = e.CommandName;
                sortText = sort.Text + "▲";
            }
            else
            {
                ViewState["SortOrder"] = ViewState["SortOrder"].ToString() == "ASC" ? "DESC" : "ASC";
    
                // 排序时更改文本
                if (sort.Text.IndexOf("▲") == -1)
                {
                    if (sort.Text.IndexOf("▼") == -1)
                        sortText = sort.Text + "▲";
                    else
                        sortText = sort.Text.Replace("▼", "▲");
                }
                else
                {
                    sortText = sort.Text.Replace("▲", "▼");
                }
            }
            ViewState["SortText"] = sortText;
        }
    }

    片段4:前端数据源解析

    <table>
            <asp:Repeater runat="server" ID="Repeater1" OnItemCommand="Repeater1_ItemCommand"
                OnItemDataBound="Repeater1_ItemDataBound">
                <HeaderTemplate>
                    <tr>
                        <th width="100">
                            <asp:LinkButton ID="ISBN" runat="server" Text="ISBN" CommandName="ISBN" />
                        </th>
                        <th width="200">
                            <asp:LinkButton ID="Title" runat="server" Text="Title" CommandName="Title" />
                        </th>
                        <th width="100">
                            Image
                        </th>
                        <th width="100">
                            <asp:LinkButton ID="Category" runat="server" Text="Category" CommandName="Category" />
                        </th>
                        <th width="100">
                            <asp:LinkButton ID="Author" runat="server" Text="Author" CommandName="Author" />
                        </th>
                        <th width="100">
                            <asp:LinkButton ID="Price" runat="server" Text="Price" CommandName="Price" />
                        </th>
                        <th width="100">
                            <asp:LinkButton ID="Package" runat="server" Text="Package" CommandName="Package" />
                        </th>
                        <th width="100">
                            <asp:LinkButton ID="Pages" runat="server" Text="Pages" CommandName="Pages" />
                        </th>
                    </tr>
                    <tr>
                        <td colspan="8" style="border-bottom: 1px solid #465c71">
                        </td>
                    </tr>
                </HeaderTemplate>
                <ItemTemplate>
                    <tr>
                        <td width="100">
                            <%# Eval("ISBN") %>
                        </td>
                        <td width="200">
                            <%# Eval("Title") %>
                        </td>
                        <td width="100">
                            <img src="<%# Eval("ImageUrl") %>" width="50" />
                        </td>
                        <td width="100">
                            <%# Eval("CategoryName") %>
                        </td>
                        <td width="100" >
                            <%# Eval("Author") %>
                        </td>
                        <td width="100" >
                            <%# Eval("Price") %>
                        </td>
                        <td width="100" >
                            <%# Eval("Package") %>
                        </td>
                        <td width="100" >
                            <%# Eval("Pages") %>
                        </td>
                    </tr>
                    <tr>
                        <td colspan="8" style="border-bottom: 1px solid #465c71">
                        </td>
                    </tr>
                </ItemTemplate>
            </asp:Repeater>
        </table>
    

    2. 传统排序方式

    在线Demo浏览:Repeater传统排序方式

    protected void Repeater1_ItemCommand(object source, RepeaterCommandEventArgs e)
    {
        // 设置排序
        SetSorting(e);
    
        if (ViewState["SortOrder"] != null)
        {
            string sortOrder = ViewState["SortOrder"].ToString();
            switch (ViewState["SortBy"].ToString())
            {
                case "ISBN":
                    Repeater1.DataSource = sortOrder == "ASC"
                                                ? DataSource.OrderBy(b => b.ISBN)
                                                : DataSource.OrderByDescending(b => b.ISBN);
                    break;
                case "Title":
                    Repeater1.DataSource = sortOrder == "ASC"
                                                ? DataSource.OrderBy(b => b.Title)
                                                : DataSource.OrderByDescending(b => b.Title);
                    break;
                case "Category":
                    Repeater1.DataSource = sortOrder == "ASC"
                                                ? DataSource.OrderBy(b => b.CategoryName)
                                                : DataSource.OrderByDescending(b => b.CategoryName);
                    break;
                case "Author":
                    Repeater1.DataSource = sortOrder == "ASC"
                                                ? DataSource.OrderBy(b => b.Author)
                                                : DataSource.OrderByDescending(b => b.Author);
                    break;
                case "Package":
                    Repeater1.DataSource = sortOrder == "ASC"
                                                ? DataSource.OrderBy(b => b.Package)
                                                : DataSource.OrderByDescending(b => b.Package);
                    break;
                case "Pages":
                    Repeater1.DataSource = sortOrder == "ASC"
                                                ? DataSource.OrderBy(b => b.Pages)
                                                : DataSource.OrderByDescending(b => b.Pages);
                    break;
            }
            Repeater1.DataBind();
        }
    }
     

    这段代码是不是看起来很悲催?这么多的Switch Case语句,如果Book类的显示字段增加了,并且都要求排序,那岂不是又得来更改这个方法 。我们想要的方式是只要知道字段的名称(e.CommandName),就能通过几行代码实现排序。反射听起来是个不错的方式。

    3. 使用反射获取排序字段

    在线Demo:Repeater 反射排序方式

    通过反射动态获取Book对象的属性的值,可以将上面的方法精简很多代码。

    protected void Repeater1_ItemCommand(object source, RepeaterCommandEventArgs e)
    {
        // 设置排序
        SetSorting(e);
    
        if (ViewState["SortOrder"] != null)
        {
            Repeater1.DataSource = ViewState["SortOrder"].ToString() == "ASC"
                                        ? DataSource.OrderBy(
                                            o => TypeHelper.GetPropertyValue(o, ViewState["SortBy"].ToString()))
                                        : DataSource.OrderByDescending(
                                            o => TypeHelper.GetPropertyValue(o, ViewState["SortBy"].ToString()));
            Repeater1.DataBind();
        }
    }

    Type类代码:

    public static class TypeHelper
    {
        public static object GetPropertyValue(object obj, string name)
        {
            return obj == null ? null : obj.GetType()
                                            .GetProperty(name)
                                            .GetValue(obj, null);
        }
    }

    4.  通过扩展方法让Linq支持字符串排序

    在线Demo:Repeater Linq 扩展方法排序方式

    Linq本身不支持字符串排序的,在Linq下我们并不能像这样去写代码:

    Repeater1.DataSource = DataSource.OrderBy(e.CommandName).ToList();

    VS会提示语法错误,因为e.CommandName是string类型,而它需要的是<TSource, TKey>参数。

    但是我们可以通过扩展方法去达到这一目的。

    在项目下添加一个LinqExtension类:

    public static class LinqExtension
    {
        public static IEnumerable<T> Sort<T>(this IEnumerable<T> source, string sortExpression)
        {
            string[] sortParts = sortExpression.Split(' ');
            var param = Expression.Parameter(typeof (T), string.Empty);
            try
            {
                var property = Expression.Property(param, sortParts[0]);
                var sortLambda = Expression.Lambda<Func<T, object>>(Expression.Convert(property, typeof (object)), param);
    
                if (sortParts.Length > 1 && sortParts[1].Equals("desc", StringComparison.OrdinalIgnoreCase))
                {
                    return source.AsQueryable<T>().OrderByDescending<T, object>(sortLambda);
                }
                return source.AsQueryable<T>().OrderBy<T, object>(sortLambda);
            }
            catch (ArgumentException)
            {
                return source;
            }
        }
    }

    sortExpression同时包含了排序字段和排序方式,传入参数时像”Name desc”这种形式。调用的方式很简单,仅一行代码:

    protected void Repeater1_ItemCommand(object source, RepeaterCommandEventArgs e)
    {
        // 设置排序
        SetSorting(e);
        if (ViewState["SortOrder"] != null)
        {
            Repeater1.DataSource = DataSource.Sort(string.Concat(e.CommandName, " ", ViewState["SortOrder"].ToString()));
            Repeater1.DataBind();
        }
    }

    5. 总结

    本文借Repeater排序这个小功能点,介绍了传统的实现方式,但并不灵活,然后介绍了在此基础上改进的反射排序方式,最后又提供了扩展方法实现排序的方式。

    一个很小的功能可以有很多方式去实现,选择最高效最简便的方式是我们努力的方向,正如文章开头提供的3个Demo一样,它们的结果一模一样,但后面的实现方式却各不相同。一个粗俗的比喻:最开始我们给自己的代码穿上了很多衣服,甚至棉衣也穿上了,但是夏天快到了,天气较热,又是在家里,我只想为代码穿一条内裤,即使内裤里面可能筛了很多东西,但是我看到的就是一条内裤。

  • 相关阅读:
    Type Safety and Type Inference
    LEARN SWIFT
    swift 类型备份
    Swift
    associatedtype关联类型
    深入理解 Swift 派发机制
    Swift中self和Self
    Postfix Self Expression
    CGContext与上下文
    eeee
  • 原文地址:https://www.cnblogs.com/keepfool/p/2405164.html
Copyright © 2020-2023  润新知