簡體   English   中英

使用帶有LinkBut​​ton和ViewState的ObjectDataSource對ListView進行排序

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

我正在使用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 ,然后使用DataBind方法重新加載ListView ObjectDataSource的Select方法中,我們讀取此ViewState值,並使用它們對數據進行排序。

在所有這些方法上都設置斷點,當我單擊LinkButton時,可以看到按此順序進行調用:

  • OnLoad
  • SortItems
  • SelectItems

我遇到的問題是,當我進入SelectItems方法時, ViewState完全為空(它具有0個鍵):如果我在頁面的Load方法上設置了一個斷點,那么我看到包含所有這些的控件只會被加載一次。 DataBind方法似乎並未觸發控件的任何加載,它似乎只是觸發了控件的新實例的SelectItems方法(這意味着,如果我不是使用ViewState而是在SortItems方法中設置了一個實例字段,進入SelectItems方法時,該字段為null)。

我確定ViewState在頁面上處於活動狀態(例如,我可以使用Firefox擴展在瀏覽器側找到ViewState鍵)。

我對頁面/控件的生命周期還不太清楚。 有人可以向我解釋一下嗎?

存在許多非常簡單的方法。

首先,您將一個內置名稱(而不是自定義CommandName )放入排序鏈接按鈕中。 名稱是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 )自動提供值,並且每當您第二次單擊命令按鈕時,數據源就會自動附加DESC (這是因為ListView會自動將排序順序的狀態保持在其viewstate中,因此,不必重新發明它!)

然后,您不需要這個丑陋的委托人就可以按字符串排序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 ,該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");

完成。

如果SelectMethod不是靜態的,則ObjectDataSource控件將創建TypeName指定的類型的新實例,並在該實例上調用該方法。

您或者需要將排序表達式的參數添加到select方法中,並在ObjectDataSource上設置SortParameterName屬性 ,或者需要處理ObjectCreating事件並將ObjectInstance設置為現有控件實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM