简体   繁体   English

使用带有LinkBut​​ton和ViewState的ObjectDataSource对ListView进行排序

[英]Sorting a ListView using an ObjectDataSource with a LinkButton and ViewState

I am using a ListView to display paginated data: 我正在使用ListView显示分页数据:

<asp:ListView ID="listOfItems" runat="server" DataSourceID="ItemsDataSource" EnableModelValidation="True" InsertItemPosition="FirstItem" ItemPlaceholderID="ItemRowContainer">
    <LayoutTemplate>
        <div class="tablecontainer">
            <div class="pagination-top">
                <custom:TablePaginationControl ID="TablePaginationControl1" runat="server" ControlID="listOfItems" ShowPageSizeList="true" />
            </div>
            <table class="list-view">
                <tr>
                    <th class="first-column" width="350px">
                        <asp:LinkButton ID="SortByName" runat="server" CommandArgument="Name" CommandName="SortMainList" OnCommand="SortItems" Text="<%$ Resources:Name %>"></asp:LinkButton>
                    </th>
                    ...
                </tr>
                <tbody>
                    <tr runat="server" id="ItemRowContainer" />
                </tbody>
            </table>
        </div>
    </LayoutTemplate>
    ...
</asp:ListView>

The datasource definition: 数据源定义:

<asp:ObjectDataSource ID="ItemsDataSource" runat="server" EnablePaging="True" InsertMethod="AddItems" SelectCountMethod="SelectItemsCount" SelectMethod="SelectItems" TypeName="SHLCentral.TheLibrary.Web.View.DocumentManagementControl, ClientPortal.Web, Version=1.0.0.0, Culture=neutral, PublicKeyToken=cd2852a10d692fb9" UpdateMethod="UpdateItems">
    ...
</asp:ObjectDataSource>

The revelant code behind is made of these two methods: 后面的启示代码由以下两种方法组成:

public IEnumerable<ListDocumentsResult> SelectItems(
    int maximumRows,
    int startRowIndex)
{
    var results = Controller.ListDocuments(new ListDocumentsRequest());

    PropertyInfo sortProperty;
    try
    {
        sortProperty = typeof (ListDocumentsResult).GetProperty((string) ViewState["mainListSortColumn"]);
    }
    catch
    {
        sortProperty = null;
    }
    Func<ListDocumentsResult, object> sortFunction = sortProperty == null
                            ? (Func<ListDocumentsResult, object>) (ldr => ldr.LastUpdatedDate)
                            : (ldr => sortProperty.GetValue(ldr, new object[0]));

    return
        (sortProperty == null || !((bool) ViewState["mainListSortAsc"])
             ? results.OrderByDescending(sortFunction)
             : results.OrderBy(sortFunction))
            .Skip(startRowIndex)
            .Take(maximumRows);
}

protected void SortItems(object sender, CommandEventArgs e)
{
    if (e.CommandName == "SortMainList")
    {
        var sortColumn = (string) e.CommandArgument;
        if ((string)ViewState["mainListSortColumn"] == sortColumn)
        {
            ViewState["mainListSortAsc"] = !(bool)ViewState["mainListSortAsc"];
        }
        else
        {
            ViewState["mainListSortAsc"] = true;
            ViewState["mainListSortColumn"] = sortColumn;
        }
        DataBind();
    }
}

So my intention this: when the users clicks on the LinkButton contained in the "Name" column header (I left out all but one column for clarity), the SortItems method is called: it sets the sorted column name and sort order into the ViewState , then reloads the ListView using the DataBind method. 因此,我的意图是:当用户单击“名称”列标题中包含的LinkButton (为清楚起见,我省略了除一列之外的所有列),将调用SortItems方法:它将已排序的列名和排序顺序设置为ViewState ,然后使用DataBind方法重新加载ListView In the Select method of the ObjectDataSource , we read this ViewState values and use them to order the data. ObjectDataSource的Select方法中,我们读取此ViewState值,并使用它们对数据进行排序。

Putting breakpoints on all these methods, I can see there is this sequence of calls when I click the LinkButton : 在所有这些方法上都设置断点,当我单击LinkButton时,可以看到按此顺序进行调用:

  • OnLoad
  • SortItems
  • SelectItems

The problem I have is that when I get to the SelectItems method, the ViewState is totally empty (it has 0 keys): if I set a breakpoint on the Load method of the page, I see the control containing all this is only loaded once. 我遇到的问题是,当我进入SelectItems方法时, ViewState完全为空(它具有0个键):如果我在页面的Load方法上设置了一个断点,那么我看到包含所有这些的控件只会被加载一次。 The DataBind method does not seem to trigger any loading of the control, it seems to be just triggering the SelectItems method of a new instance of the control (meaning that if, instead of using ViewState , I set an instance field in the SortItems method, the field is null when getting in the SelectItems method). DataBind方法似乎并未触发控件的任何加载,它似乎只是触发了控件的新实例的SelectItems方法(这意味着,如果我不是使用ViewState而是在SortItems方法中设置了一个实例字段,进入SelectItems方法时,该字段为null)。

I am sure that the ViewState is active on the page (I can find the ViewState keys on the browser side using a Firefox extension for instance). 我确定ViewState在页面上处于活动状态(例如,我可以使用Firefox扩展在浏览器侧找到ViewState键)。

There is something not quite clear to me about the life cycle of the page/control. 我对页面/控件的生命周期还不太清楚。 Could someone explain what it is to me? 有人可以向我解释一下吗?

There exist much, much simpler approach. 存在许多非常简单的方法。

First, instead of a custom CommandName , you put a built-in name into the sort link button. 首先,您将一个内置名称(而不是自定义CommandName )放入排序链接按钮中。 The name is Sort . 名称是Sort

You have then 那你有

   <asp:LinkButton ID="SortByName" runat="server" CommandArgument="Name" CommandName="Sort" />

Then, on your ObjectDataSource you add the SortParameterName to be something like OrderBy : 然后,在您的ObjectDataSource ,添加SortParameterName类似于OrderBy

   <ObjectDataSource .... SortParameterName="OrderBy" />

Then you modify your data provider method to be: 然后,将数据提供者方法修改为:

 public IEnumerable<ListDocumentsResult> SelectItems(
   string OrderBy,
   int maximumRows,
   int startRowIndex)

The data source will provide the value automatically based on the command argument ( Name ) and it will automatically append DESC whenever you click the command button for the second time (it is because the ListView persists the state of sort order in its viewstate automatically, you don't have to reinvent this!) 数据源将根据命令参数( Name )自动提供值,并且每当您第二次单击命令按钮时,数据源就会自动附加DESC (这是因为ListView会自动将排序顺序的状态保持在其viewstate中,因此,不必重新发明它!)

Then, you don't need this ugly delegates to order by strings for linq. 然后,您不需要这个丑陋的委托人就可以按字符串排序linq。 Instead, download the Dynamic Linq library: 而是下载Dynamic Linq库:

http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx http://weblogs.asp.net/scottgu/archive/2008/01/07/dynamic-linq-part-1-using-the-linq-dynamic-query-library.aspx

find the Dynamic.cs file, include it in your project and it will add a bunch of additional linq operators, including the OrderBy which accepts strings and which automatically supports DESC (!). 找到Dynamic.cs文件,将其包含在您的项目中,它将添加一堆其他linq运算符,包括OrderBy ,该OrderBy接受字符串并自动支持DESC (!)。

You then just 然后你就

 public IEnumerable<ListDocumentsResult> SelectItems(
   string OrderBy,
   int maximumRows,
   int startRowIndex)
 {

     Controller.ListDocuments(new ListDocumentsRequest())
        .OrderBy(OrderBy)
        .Skip(startRowIndex)
        .Take(maximumRows);
 }

This is just as simple! 这很简单!

Be warned though that there's a small bug (or an inconvenience) in the dynamic linq - it throws an exception when the sort order is empty. 请注意,动态linq中存在一个小错误(或不便之处)-当排序顺序为空时,它将引发异常。

Find then this code (line 47 and down) 然后查找此代码(第47行及以下)

    public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values) {
        if (source == null) throw new ArgumentNullException("source");
        if (ordering == null) throw new ArgumentNullException("ordering");

and change it manually to 并手动将其更改为

    public static IQueryable OrderBy(this IQueryable source, string ordering, params object[] values) {
        if ( string.IsNullOrEmpty( ordering ) ) return source;
        if (source == null) throw new ArgumentNullException("source");
        if (ordering == null) throw new ArgumentNullException("ordering");

Done. 完成。

If the SelectMethod is not static, the ObjectDataSource control will create a new instance of the type specified in TypeName and call the method on that instance. 如果SelectMethod不是静态的,则ObjectDataSource控件将创建TypeName指定的类型的新实例,并在该实例上调用该方法。

You either need to add a parameter for the sort expression to your select method and set the SortParameterName property on the ObjectDataSource , or you need to handle the ObjectCreating event and set the ObjectInstance to the existing control instance. 您或者需要将排序表达式的参数添加到select方法中,并在ObjectDataSource上设置SortParameterName属性 ,或者需要处理ObjectCreating事件并将ObjectInstance设置为现有控件实例。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM