[英]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.