0

我正在使用 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>

数据源定义:

<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>

背后的相关代码是由这两种方法组成的:

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();
    }
}

所以我的意图是:当用户单击LinkButton“名称”列标题中包含的内容时(为了清楚起见,我只留下一列),SortItems调用该方法:它将排序的列名称和排序顺序设置为ViewState,然后重新加载的ListView使用DataBind方法。在 的 Select 方法中ObjectDataSource,我们读取这些ViewState值并使用它们对数据进行排序。

在所有这些方法上设置断点,当我单击时,我可以看到有以下调用序列LinkButton

  • OnLoad
  • SortItems
  • SelectItems

我遇到的问题是,当我到达该SelectItems方法时,它ViewState是完全空的(它有 0 个键):如果我在页面的 Load 方法上设置一个断点,我会看到包含所有这些的控件只加载一次。该DataBind方法似乎没有触发控件的任何加载,它似乎只是触发了SelectItems控件的新实例的方法(这意味着如果ViewState我在方法中设置了一个实例字段而不是 using ,SortItems则该字段为 null进入SelectItems方法时)。

我确信ViewState页面上是活动的(例如,我可以ViewState使用 Firefox 扩展在浏览器端找到键)。

关于页面/控件的生命周期,我不太清楚。有人可以解释一下对我来说是什么吗?

4

2 回答 2

3

存在很多非常简单的方法。

CommandName首先,您将内置名称而不是 custom放入排序链接按钮。名字是Sort

你有然后

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

然后,在您的ObjectDataSource身上添加SortParameterName类似于OrderBy

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

然后将数据提供者方法修改为:

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

Name数据源将根据命令参数DESCListView必须重新发明这个!)

然后,您不需要这个丑陋的代表按字符串为 linq 排序。相反,下载 Dynamic Linq 库:

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

找到该Dynamic.cs文件,将其包含在您的项目中,它会添加一堆额外的 linq 运算符,包括OrderBy接受字符串和自动支持DESC(!)。

那你就

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

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

这很简单!

尽管动态 linq 中存在一个小错误(或不便),但请注意 - 当排序顺序为空时,它会引发异常。

然后找到此代码(第 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");

并手动将其更改为

    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");

完毕。

于 2012-11-07T13:39:25.397 回答
2

如果SelectMethod不是静态的,ObjectDataSource控件将创建一个指定类型的新实例TypeName并调用该实例上的方法。

您需要将排序表达式的参数添加到您的 select 方法并在上设置SortParameterName属性ObjectDataSource,或者您需要处理ObjectCreating事件并将 设置ObjectInstance为现有控件实例。

于 2012-11-07T13:41:46.500 回答