asp.net mvc 3 webgrid 排序仍然存在 ?sortdir=ASC

发布于 2024-10-08 15:39:58 字数 2111 浏览 3 评论 0原文

我正在 asp.net mvc 中尝试一些网格。 Microsoft 在 mvc 3 的预发行版中也有一个网格,所以我想我会尝试一下。

基本功能很容易实现,但是当涉及到排序时,我遇到了一些问题。 网格按照 url 进行排序。在 url 中,您可以按以下方式获得排序列和排序方向: ?sortdir=ASC&sort=ABONNMENT

现在您可能会期望在对特定列进行排序后,该列上的 sortdir 查询字符串将更改为 ?sortdir=DESC 但事实并非如此。它保留 ?sortdir=ASC 。 有谁知道这是一个错误还是一个功能,以及如何解决这个问题?

另一个非常烦人的事情:如果我单击排序链接,就会完成 httpget 请求。 因此我失去了我的模型。因为页面上可以过滤网格(搜索功能),所以我想将其保留在模型中。 这会更容易&在我看来,将这些数据放入模型状态比将其存储在会话状态中更干净的解决方案。 是否可以更改排序标头链接的行为,以便执行 http post?

对此有什么想法或想法吗? Tnx 寻求帮助。

greetz, Koen

视图的代码如下:

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<table>
    <tr>
        <td>
            <h1 class="normal">List of subscription</h1>
        </td>
        <td>

        </td>
    </tr>
</table>
<% using (Html.BeginForm("List", "Subscription", FormMethod.Post)) { %>

<table border="0" cellpadding="0" cellspacing="5">
    <tr>
        <td>
            Search By
        </td>
        <td>
            <%: Html.DropDownListFor(m => m.SearchByColumn, Ogone.FrontEnd.Web.Controllers.SubscriptionController.SubscriptionSearchList) %>
        </td>
        <td>
            <%: Html.TextBoxFor(m => m.SearchByText) %>
        </td>
        <td>
            <input name="button" type="submit" value="Search" />
        </td>
    </tr>
</table>

<div>
<%  
var grid = new System.Web.Helpers.WebGrid(Model.SubscriptionList,  
              columnNames: new List<string>(){"Title"},  
              canPage:false);  
 %> 
<%= grid.GetHtml(columns: grid.Columns(
             grid.Column(format: (item) => Html.ActionLink("Edit", "Edit", new { id = item.ID })),
             grid.Column("ID"),
             grid.Column("ISP"),
             grid.Column("ABONNEMENT"),
             grid.Column("MODE"),
             grid.Column("SETUPFEE"),
             grid.Column("MONTHLYFEE"))
             ) %>
</div>

I'm experimenting a bit with several grids in asp.net mvc.
Microsoft has a grid too know in the prerelease of mvc 3 so I thought I'll try that one out.

The basic functionality is quite easy to implement but when it comes to sorting, I'm having some problems.
The grid handles its sorting by the url. In the url you have the sort column and the sort direction in the following way:
?sortdir=ASC&sort=ABONNEMENT

Now you would expect that after you've done the sorting on the certain column, the sortdir querystring on that column would change to ?sortdir=DESC
but it doesn't. It stays ?sortdir=ASC .
Does anybody knows if this is a bug or a feature, and how to solve this?

Another very annoying thing: if I click on a sort link, an httpget request is done.
Because of this I loose my model. Because there is the possibility on the page to filter the grid (search functionality), I want to preserve this in the model.
It would be a much easier & cleaner solution in my opinion to put this data in the model state, than to store it in the session state.
Is it possible to change the behaviour of the sorting header links so a http post is executed?

Any ideas or thoughts on this?
Tnx for the help.

greetz, Koen

The code of the view is the following:

<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">

<table>
    <tr>
        <td>
            <h1 class="normal">List of subscription</h1>
        </td>
        <td>

        </td>
    </tr>
</table>
<% using (Html.BeginForm("List", "Subscription", FormMethod.Post)) { %>

<table border="0" cellpadding="0" cellspacing="5">
    <tr>
        <td>
            Search By
        </td>
        <td>
            <%: Html.DropDownListFor(m => m.SearchByColumn, Ogone.FrontEnd.Web.Controllers.SubscriptionController.SubscriptionSearchList) %>
        </td>
        <td>
            <%: Html.TextBoxFor(m => m.SearchByText) %>
        </td>
        <td>
            <input name="button" type="submit" value="Search" />
        </td>
    </tr>
</table>

<div>
<%  
var grid = new System.Web.Helpers.WebGrid(Model.SubscriptionList,  
              columnNames: new List<string>(){"Title"},  
              canPage:false);  
 %> 
<%= grid.GetHtml(columns: grid.Columns(
             grid.Column(format: (item) => Html.ActionLink("Edit", "Edit", new { id = item.ID })),
             grid.Column("ID"),
             grid.Column("ISP"),
             grid.Column("ABONNEMENT"),
             grid.Column("MODE"),
             grid.Column("SETUPFEE"),
             grid.Column("MONTHLYFEE"))
             ) %>
</div>

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

孤檠 2024-10-15 15:39:58

发生这种情况是因为网格列名称必须与您的字段或属性相对应。在网格标题中生成 url 的方法将 url 查询字符串中的“排序”与有界列和网格列名称进行比较。他们三人一定是同一个人。如果列名称的定义配置不正确,则将无法正确生成 url。

无论如何..这里是一些正确定义的列名称的示例。

这里我们有示例域类要显示

public class Person
{
    public string FirstName;
    public string LastName;
    public Address LivesIn;
}

public class Address
{
    public string Country;
    public string City;
}

现在让我们显示列表

使用您的列名作为字段

grid.Column("FirstName"),
grid.Column("LastName"),
grid.Column("LivesIn.City"),
grid.Column("LivesIn.Country")

...所有列都有正确的排序网址

如果您在列名中输入错误,则会出现异常

grid.Column("FirstName"),
grid.Column("MyLastName"), <-- this throws exception
grid.Column("LivesIn.City"),
grid.Column("LivesIn.Country")

但是您可以使用格式并且不会抛出异常

grid.Column("FirstName"),
grid.Column("MyLastName", format: item => item.LastName</text>),
grid.Column("LivesIn.City"),
grid.Column("LivesIn.Country")

...但是 MyLastName 列的排序 url 会很糟糕!始终 sortDir=ASC

您需要使用好的列名来拥有正确的排序 url 和自定义格式,所以……

grid.Column("FirstName"),
grid.Column("LastName", format: item => item.LastName),
grid.Column("LivesIn.City"),
grid.Column("LivesIn.Country")

一切都可以

复杂类型怎么样?

grid.Column("FirstName"),
grid.Column("LastName"),
grid.Column("LivesIn.MyNonExistingField", format: item => item.LivesIn.City),
grid.Column("LivesIn.Country")

....哇...一切都好..那是bug的孩子..列“LivesIn.MyNonExistingField”有正确的排序网址。

好的...如果我们不想暴露我们的域结构怎么办?然后我们需要在绑定期间添加列名称列表

var grid = new WebGrid(persons, columnNames: new [] { "Foo" });
-- or --
grid.Bind(persons, columnNames: new [] { "Foo" });

grid.Column("Foo", format: item => item.FirstName),
grid.Column("LastName"),
grid.Column("LivesIn.MyNonExistingField", format: item => item.LivesIn.City),
grid.Column("LivesIn.Country")

..现在 Foo 列具有正确的排序 url

但要小心!还有另一个错误。

如果我们将手动列名称添加到绑定中,则将跳过所有列,直到找到手动列。示例:

var grid = new WebGrid(persons, columnNames: new [] { "Foo" });
-- or --
grid.Bind(persons, columnNames: new [] { "Foo" });

grid.Column("FirstName"),
grid.Column("Foo", format: item => item.LastName),
grid.Column("LivesIn.MyNonExistingField", format: item => item.LivesIn.City),
grid.Column("LivesIn.Country")

...列“FirstName”的排序 url 将无法正确生成...sortDir=ASC 始终...要解决此问题,还需要添加一个“FirstName”作为列名称,如下所示:

var grid = new WebGrid(persons, columnNames: new [] { "FirstName", "Foo" });
-- or --
grid.Bind(persons, columnNames: new [] { "FirstName", "Foo" });

grid.Column("FirstName"),
grid.Column("Foo", format: item => item.LastName),
grid.Column("LivesIn.MyNonExistingField", format: item => item.LivesIn.City),
grid.Column("LivesIn.Country")

@Kohen

删除您的列中的 columnNames此处代码

var grid = new System.Web.Helpers.WebGrid(Model.SubscriptionList,  
          columnNames: new List<string>(){"Title"},  
          canPage:false);

...或添加所有列名称,例如“ID”、“ISP”等

This happens because grid column names must correspond to your fields or properties. Method which generates url in grid header compares "sort" from url query string with bounded columns and with grid column name. The three of them must be the same. If definition of your column name is not configured properly, the url will not be generated correctly.

Anyway .. here is some examples of properly defined column names.

Here we have sample domain class to display

public class Person
{
    public string FirstName;
    public string LastName;
    public Address LivesIn;
}

public class Address
{
    public string Country;
    public string City;
}

Now lets display List

Use your column names as fields

grid.Column("FirstName"),
grid.Column("LastName"),
grid.Column("LivesIn.City"),
grid.Column("LivesIn.Country")

... all columns has correct sorting url

If you make a typo in column name you got exception

grid.Column("FirstName"),
grid.Column("MyLastName"), <-- this throws exception
grid.Column("LivesIn.City"),
grid.Column("LivesIn.Country")

But you can use format and there will be no exception thrown

grid.Column("FirstName"),
grid.Column("MyLastName", format: item => item.LastName</text>),
grid.Column("LivesIn.City"),
grid.Column("LivesIn.Country")

... but sorting url for column MyLastName will be BAD !!! all the time sortDir=ASC

You need to use good column name to has proper sorting url and custom format so ...

grid.Column("FirstName"),
grid.Column("LastName", format: item => item.LastName),
grid.Column("LivesIn.City"),
grid.Column("LivesIn.Country")

... everything is ok

How about complex type ?

grid.Column("FirstName"),
grid.Column("LastName"),
grid.Column("LivesIn.MyNonExistingField", format: item => item.LivesIn.City),
grid.Column("LivesIn.Country")

.... wow ... everything is ok .. that's kid of bug .. column "LivesIn.MyNonExistingField" has proper sorting url.

Ok ... What if we don't want to expose our domain structure. Then we need to add list of column names during binding

var grid = new WebGrid(persons, columnNames: new [] { "Foo" });
-- or --
grid.Bind(persons, columnNames: new [] { "Foo" });

grid.Column("Foo", format: item => item.FirstName),
grid.Column("LastName"),
grid.Column("LivesIn.MyNonExistingField", format: item => item.LivesIn.City),
grid.Column("LivesIn.Country")

.. now Foo column has proper sorting url

But careful !!! There is another bug.

If we add manual column names to binding then all column will be skipped until manual column is found. Example :

var grid = new WebGrid(persons, columnNames: new [] { "Foo" });
-- or --
grid.Bind(persons, columnNames: new [] { "Foo" });

grid.Column("FirstName"),
grid.Column("Foo", format: item => item.LastName),
grid.Column("LivesIn.MyNonExistingField", format: item => item.LivesIn.City),
grid.Column("LivesIn.Country")

... sorting url for column "FirstName" will not be generated correctly ... sortDir=ASC all the time ...to fix this add also a "FirstName" as column name like this:

var grid = new WebGrid(persons, columnNames: new [] { "FirstName", "Foo" });
-- or --
grid.Bind(persons, columnNames: new [] { "FirstName", "Foo" });

grid.Column("FirstName"),
grid.Column("Foo", format: item => item.LastName),
grid.Column("LivesIn.MyNonExistingField", format: item => item.LivesIn.City),
grid.Column("LivesIn.Country")

@Kohen

Remove columnNames in your code here

var grid = new System.Web.Helpers.WebGrid(Model.SubscriptionList,  
          columnNames: new List<string>(){"Title"},  
          canPage:false);

... or add there all your column names like "ID", "ISP", etc

黎歌 2024-10-15 15:39:58

我一直在考虑解决该问题的方法,并且找到了一个。

我将一个额外的参数注入到查询字符串集合中。这样我就可以将搜索过滤器放入查询字符串中。

通常查询字符串集合是只读的,但我找到了一些代码来解决这个问题。

将参数添加到查询字符串的代码:

            public static void Add(string name, string value)
            {
                    NameValueCollection qs = System.Web.HttpContext.Current.Request.QueryString;
                    qs = (NameValueCollection)System.Web.HttpContext.Current.Request.GetType().GetField("_queryString", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(System.Web.HttpContext.Current.Request);
                    PropertyInfo readOnlyInfo = qs.GetType().GetProperty("IsReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
                    readOnlyInfo.SetValue(qs, false, null);
                    qs[name] = value;
                    readOnlyInfo.SetValue(qs, true, null);
            }

新控制器代码:

            public ActionResult Index(string SearchFilter)
            {
                    // check querystring search
                    if (string.IsNullOrEmpty(SearchFilter) && !String.IsNullOrEmpty(Request.QueryString["search"]))
                            SearchFilter = Request.QueryString["search"];

                    var model = new Models.SubscriptionListModel { SearchFilter = SearchFilter };

                    if (string.IsNullOrEmpty(SearchFilter))
                    {
                            model.SubscriptionList = _subscriptionHandler.ReadWhereIdLessThanThousand();
                    }
                    else
                    {
                            // add search filter to the querystring
                            Common.QueryString.Add("search", SearchFilter);
                            model.SubscriptionList = _subscriptionHandler.ReadWhereContains(SearchFilter);
                    }

                    if (Request.IsAjaxRequest())
                    {
                            return View("SubscriptionList", model);
                    }
                    else
                    {
                            return View("Index", model);
                    }
            }

如果有人有更清晰的解决方案来解决此问题,仍然欢迎提出建议:-)

I've been thinking about a workaround for the problem, and I've found one.

I inject an extra parameter into the querystring collection. That way I can put the search filter into the querystring.

Normally the querystring collection is readonly, but I've found some code to fix this.

Code to add parameter to querystring:

            public static void Add(string name, string value)
            {
                    NameValueCollection qs = System.Web.HttpContext.Current.Request.QueryString;
                    qs = (NameValueCollection)System.Web.HttpContext.Current.Request.GetType().GetField("_queryString", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(System.Web.HttpContext.Current.Request);
                    PropertyInfo readOnlyInfo = qs.GetType().GetProperty("IsReadOnly", BindingFlags.NonPublic | BindingFlags.Instance);
                    readOnlyInfo.SetValue(qs, false, null);
                    qs[name] = value;
                    readOnlyInfo.SetValue(qs, true, null);
            }

New controller code:

            public ActionResult Index(string SearchFilter)
            {
                    // check querystring search
                    if (string.IsNullOrEmpty(SearchFilter) && !String.IsNullOrEmpty(Request.QueryString["search"]))
                            SearchFilter = Request.QueryString["search"];

                    var model = new Models.SubscriptionListModel { SearchFilter = SearchFilter };

                    if (string.IsNullOrEmpty(SearchFilter))
                    {
                            model.SubscriptionList = _subscriptionHandler.ReadWhereIdLessThanThousand();
                    }
                    else
                    {
                            // add search filter to the querystring
                            Common.QueryString.Add("search", SearchFilter);
                            model.SubscriptionList = _subscriptionHandler.ReadWhereContains(SearchFilter);
                    }

                    if (Request.IsAjaxRequest())
                    {
                            return View("SubscriptionList", model);
                    }
                    else
                    {
                            return View("Index", model);
                    }
            }

If anyone has a cleaner solution to fix this, suggestions are still welcome :-)

昵称有卵用 2024-10-15 15:39:58

我不确定为什么 DESC 不切换为 ASC。我有一个类似的例子,它工作得很好。尝试使用 ajax 容器(ajaxUpdateContainerId)。这可能会有所帮助,如果没有其他办法的话,它可以解决您在 httpget 请求中遇到的问题,维护您的搜索结果。这是我所拥有的:(我正在使用剃刀,但应该很容易转换)。

只需添加新属性: ajaxUpdateContainerId: "div_name"

用 ID 为 div_name 的 div 包裹网格

@{
var grid = new System.Web.Helpers.WebGrid(Model.SubscriptionList, canPage:false, ajaxUpdateContainerId: "grid");  
}
<div id="grid">
    @grid.GetHtml(columns: grid.Columns(  
    grid.Column(format:(item) => Html.ActionLink("Edit", "Edit", new { id=item.Id })),
    grid.Column("ISP"),
    grid.Column("ABONNEMENT"))) 
</div>

祝你好运,希望它有所帮助!

I'm not sure why DESC isn't switchign to ASC. I have a similar example and it works just fine. Ttry using the ajax container(ajaxUpdateContainerId). This could help, if nothing else it would solve the issue you are having with the httpget request, maintaining your search result. Here is what I have: (I'm using razor, but should be easy enough to convert).

Simply add the new property: ajaxUpdateContainerId: "div_name"

Wrap the grid with a div having an ID of div_name

@{
var grid = new System.Web.Helpers.WebGrid(Model.SubscriptionList, canPage:false, ajaxUpdateContainerId: "grid");  
}
<div id="grid">
    @grid.GetHtml(columns: grid.Columns(  
    grid.Column(format:(item) => Html.ActionLink("Edit", "Edit", new { id=item.Id })),
    grid.Column("ISP"),
    grid.Column("ABONNEMENT"))) 
</div>

Best of luck, hope it helps!

请别遗忘我 2024-10-15 15:39:58

我通过设置 'SortColumn' 属性在 MVC 4 中解决了这个问题。网格的值到“排序”查询字符串参数的值:

grid = new WebGrid(...
grid.Bind(Model...

grid.SortColumn = this.Request.QueryString["sort"];

@grid.GetHtml(columns:...

我注意到对于我的模型“SortColumn”道具中的“日期”列。无论“sort”查询字符串参数的值如何,都被设置为默认排序列的名称...

I fixed this issue in MVC 4 by setting the 'SortColumn' prop. of the grid to the value of "sort" Query String param.:

grid = new WebGrid(...
grid.Bind(Model...

grid.SortColumn = this.Request.QueryString["sort"];

@grid.GetHtml(columns:...

I noticed that for 'Date' columns in my model 'SortColumn' prop. was set to the name of default sort column regardless of the value of "sort" Query String param...

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文