10

Asp.net mvc を学習しようとしています。形とは違うのは分かっているので、考え方を変える必要があるのか​​もしれません。私の問題は webgrid に関するものです。ページに webgrid を追加し、Post で検索ボタンを押すと、ページャーなどでテーブルがレンダリングされます。しかし、ページャーのリンクはフォームを投稿するのではなく、単なるリンクであり、フォームのデータをすべて失いました。

コントローラーには、get 用と post 用の 2 つのインデックス メソッドがあります。get i do何もしないために、この場合は新しいビューモデルを作成します 検索クラス そしてそれをビューに設定します。私のポストメソッドでは、ビューモデルを取得して検索し、塗りつぶされたビューモデルをビューに設定します。

問題 : webgrid はページャーをリンクとしてレンダリングするため、get のインデックスに入力されますが、ポスト リクエストではないため、フォーム フィールドが入力されておらず、検索でまったく同じ結果セットが提供されません。

多分サンプルコードはそれをよりよく説明することができます.

意見:

<form action="" method="post">

Esas no : @Html.TextBoxFor(x=>x.Name)
Yil : @Html.TextBoxFor(x=>x.Year)

<input type="submit" value="Search" />

<hr />
@ViewBag.Message
<hr />

@{ var grid = new WebGrid(Model.Results,rowsPerPage:5);}

@grid.GetHtml(tableStyle:"table",htmlAttributes:new {id="tbl"} )

</form>

これが私のコントローラーです。検索はIndex Postメソッドで行われ、ビューモデルクラスだけがあります。

    private ISearchContext _sc;

    public  MyController(ISearchContext sc)
    {
        _dc = dc;
    }

    //
    // GET: /Dava/

    public ActionResult Index()
    {
        var search = new Search();
        ViewBag.Message = "";
        return View(search);
    }

    [HttpPost]
    public ActionResult Index(Search search)
    {

        Search sres = _dc.SearchFromRepository(search);
        ViewBag.Message = String.Format("Count:{0} ",sres.Results.Count);
        return View(sres);
    }

検索モデル クラスは次のようになります。

public class Search
{
    public int Year { get; set; }
    public string Name { get; set; }


    public IList<Item> Results { get; set; }

    public Search()
    {
        Results = new List<Item>();
    }
}
4

4 に答える 4

9

この問題を解決する 1 つの方法は、javascript を使用し、任意のページャー リンクのクリック イベントをサブスクライブしてから、目的のページの値を取得し、それをフォームの非表示フィールドに挿入して、フォームをサーバーに送信することです。他の 2 つの値も送信されます。

Pageそのため、ビュー モデルに null 許容整数プロパティを追加しSearch、対応する非表示フィールドをフォームに追加して、選択したページ番号を含めることから始めます。

@Html.HiddenFor(x => x.Page, new { id = "page" })

次に必要なのは、ページャー リンクの .click イベントをサブスクライブするための小さな JavaScript スニペットをページに追加することだけです。

$(function () {
    $('tfoot a').click(function () {
        // when the user clicks on any of the pager links
        // try to extract the page number from the link and
        // set the value of the hidden field
        var page = this.href.match(/page=([0-9])+/)[1];
        $('#page').val(page);

        // submit the form so that the POST action is invoked
        // passing along the search criteria (Name and Year) along
        // with the page hidden field value to the Index action
        $('form').submit();

        // cancel the default action of the link which is to simply redirect
        // to the Index action using a GET verb.
        return false;
    });
});
于 2011-06-14T13:30:42.317 に答える
5

JavaScript を使用しない回避策を次に示します。

私が見ている問題は、ページング リンクが、検索フィルターのように保存する必要があるルート情報を受信しないことです。IMOこれは露骨な見落としです!ここで少し余分に考えれば、多くの頭痛が解消されたはずです!

この手法は、WebGrid の組み込みページングを「破棄」し、ヘルパーを使用して必要な貴重なルート データと共にページング リンクを生成します。

完了したら、WebGrid をグリッドのみとしてレンダリングし、ヘルパーを使用してページング リンクを作成します。ここでの利点の 1 つは、それらを上下に配置できることです。

NuGet がソリューションに入れる Pager.css で提供されているものと同様の CSS を使用しようとしました。ヘルパーは一部の人にとっては十分に完成しているはずですが、簡単に拡張できます。

新規 新規 新規Ajax バージョンでヘルパーを更新しました。私は Razor ヘルパーに少し慣れていないので、一般的なテンプレートを使用するようにリファクタリングする方法がわかりませんでした。誰かお願いします?重要な追加の詳細は、渡しAjaxOptionsて必ずPOST動詞として使用することです。そうしないと、正しいコントローラー メソッドにならない可能性があります。

ヘルパー (App_Code/LocalHelpers.cshtml):

@helper DoPager(System.Web.Mvc.HtmlHelper hh, string pageActionName, WebGrid grid, int maxPageLinks, object rvd) {
<div class="pager">
<div class="pageof">Page <b>@(grid.PageIndex + 1)</b> of <b>@grid.PageCount</b></div>
@if (grid.PageCount > 1) {
<ul>
<li>
@{ RouteValueDictionary rvdp1 = new RouteValueDictionary(rvd);
   rvdp1.Add("Page", 1);
}
@hh.ActionLink("<<", pageActionName, rvdp1)
</li>
@{ int start = Math.Max(0, grid.PageIndex - maxPageLinks / 2); }
@for (int ix = 0; ix + start < grid.PageCount; ix++) {
    int pageno = start + ix + 1;
    var css = hh.Raw(pageno - 1 == grid.PageIndex ? " class=\"highlighted\"" : "");
    RouteValueDictionary rvdp = new RouteValueDictionary(rvd);
    rvdp.Add("Page", pageno);
<li@css>
@hh.ActionLink(pageno.ToString(), pageActionName, rvdp)
</li>
    if (ix >= maxPageLinks) { break; }
}
<li>
@{ RouteValueDictionary rvdpX = new RouteValueDictionary(rvd);
   rvdpX.Add("Page", grid.PageCount);
}
@hh.ActionLink(">>", pageActionName, rvdpX)
</li>
</ul>
}
</div>
}
@helper DoAjaxPager(System.Web.Mvc.AjaxHelper aa, System.Web.Mvc.Ajax.AjaxOptions aopts, System.Web.Mvc.HtmlHelper hh, string pageActionName, WebGrid grid, int maxPageLinks, object rvd) {
<div class="pager">
<div class="pageof">Page <b>@(grid.PageIndex + 1)</b> of <b>@grid.PageCount</b></div>
@if (grid.PageCount > 1) {
<ul>
<li>
@{ RouteValueDictionary rvdp1 = new RouteValueDictionary(rvd);
   rvdp1.Add("Page", 1);
}
@aa.ActionLink("<<", pageActionName, rvdp1, aopts)
</li>
@{ int start = Math.Max(0, grid.PageIndex - maxPageLinks / 2); }
@for (int ix = 0; ix + start < grid.PageCount; ix++) {
    int pageno = start + ix + 1;
    var css = hh.Raw(pageno - 1 == grid.PageIndex ? " class=\"highlighted\"" : "");
    RouteValueDictionary rvdp = new RouteValueDictionary(rvd);
    rvdp.Add("Page", pageno);
<li@css>
@aa.ActionLink(pageno.ToString(), pageActionName, rvdp, aopts)
</li>
    if (ix >= maxPageLinks) { break; }
}
<li>
@{ RouteValueDictionary rvdpX = new RouteValueDictionary(rvd);
   rvdpX.Add("Page", grid.PageCount);
}
@aa.ActionLink(">>", pageActionName, rvdpX, aopts)
</li>
</ul>
}
</div>
}

意見:

<center>
@LocalHelpers.DoPager(Html, "Index", grid, 10, new { CurrentFilter = ViewBag.CurrentFilter })
</center>
@grid.Table(
    tableStyle: "centerit",
    columns: grid.Columns(
        grid.Column(format: @<span>@Html.ActionLink("Edit", "Edit", new { id = item.ID }) | @Html.ActionLink("Details", "Details", new { id = item.ID }) | @Html.ActionLink("Delete", "Delete", new { id = item.ID })</span>),
            grid.Column("PartNumber", "Part Number"),
            grid.Column("Description", "Description"),
            grid.Column("Regex", "Regex")
            )
        )
<center>
@LocalHelpers.DoPager(Html, "Index", grid, 10, new { CurrentFilter = ViewBag.CurrentFilter })
</center>

私の見解では、何をフィルタリングするかを知るために「CurrentFilter」をリサイクルしています。これは、コントローラ アクション (図示されていません) に接続します。

于 2011-08-12T15:37:50.070 に答える
3

Ok。この問題を完全に解決する必要がある AJAX と部分ビューを使用した、より洗練されたソリューションがあります。

これは私のモデルです:

public class SearchResultModel
{
        public string SearchText{ get; set; }
        public List<YourObject> Results { get; set; }
        public int TotalResults { get; set; }
}

検索ビューは次のように構成されています。

@model SearchResultModel
@using (Ajax.BeginForm("SearchAction", "SearchController", new AjaxOptions{UpdateTargetId = "data-grid", HttpMethod="Post"}))
{
        @Html.TextBoxFor(m => m.SearchText)
        <input class="myButton" type="submit" value="Search" />
}
<br />
<div id="data-grid">
       @Html.Partial("SearchResults", new SearchResultModel())
</div>

SearchResults の部分ビューは次のとおりです。

@model SearchResultModel
@{
    if (Model.Results != null && Model.Results.Count > 0)
    {
            var grid = new WebGrid(canPage: true, rowsPerPage: 10, canSort: true, ajaxUpdateContainerId: "grid");
            grid.Bind(Model.Results, rowCount: Model.TotalResults, autoSortAndPage: false);
            grid.Pager(WebGridPagerModes.All);

            @grid.GetHtml(htmlAttributes: new { id = "grid" },
            columns: grid.Columns(
                grid.Column("YourColumn1"),
                grid.Column("YourColumn2"),
                grid.Column("YourColumn3")
            ),
            tableStyle: "datatable",
                rowStyle: "datatable-normal",
                    alternatingRowStyle: "datatable-alt"
            );
    }
    else
    {
    <span>No Results</span>
    }
}

最後に、コントローラーは次のとおりです。

public class SearchController
{
        public ActionResult SearchAction(SearchResultModel model)
        {
            return RedirectToAction("SearchResults", new { id = model.SearchText });
        }

        public ActionResult SearchResults(string id)
        {
            string searchText = id;
            int page = 1;
            if(Request["page"] != null)
                int.TryParse(Request["page"], out page);

            SearchResultModel model = new SearchResultModel();
            //Populate model according to search text and page number
            //........
            //........
            return PartialView(model);
        }
}

これが誰かの時間と不安を救うのに役立つことを願っています!

于 2012-06-11T19:49:38.193 に答える
0

私の答えには、Session での検索を維持することが含まれます。それ以上のことはありません。このソリューションは、実際の状況に適応させることができ、特定のクラスや JQuery を必要としないため、優れています。

マジック トリックは、Index ActionResult (またはグリッド ページをデフォルトの動作でレンダリングするデフォルトの ActionResult) 内で発生します。

コード例:

    [HttpGet]
    public ActionResult Index()//My default action result that will render the grid at its default situation
    {
        SearchViewModel model = new SearchViewModel(); 

        if (Request.IsAjaxRequest()) //First trick is here, this verification will tell you that someone sorted or paged the grid.
        {
            if (Session["SearchViewModel"] != null) //If session is not empty, you will get the last filtred values from it.
                model = (SearchViewModel)Session["SearchViewModel"];
        }
        else // If it is not an AjaxRequest, you have to clear your Session, so new requests to Index with default behavior won't display filtred values.
        {
            Session["SearchViewModel"] = null;
        }

        model.GridResult = ExecuteFilter(model); // OPITIONAL! This code dependes on how is your real world situation. Just remember that you need to return a default behavior grid if the request was not called by the WebGrid, or return filtred results if WebGrid requested.
        return View(model);
    }

したがって、これがデフォルトの ActionResult になります。リクエストが WebGrid のページング イベントまたは並べ替えイベントによって呼び出されたかどうかを確認し、フィルタリングされた結果を返すか、通常の動作結果を返すかを決定します。

次のステップは、検索 POST ActionResult です。

    [HttpPost]
    public ActionResult Index(SearchViewModel pesquisa) // IMPORTANT!! It is necessary to be the SAME NAME of your GET ActionResult. The reason for that I know, but won't discuss here because it goes out of the question.
    {
        SearchViewModel model = new SearchViewModel();
        model.GridResult = ExecuteFilter(pesquisa); // Execute your filter
        Session["SearchViewModel"] = model; //Save your filter parameters on Session.
        return View("Index", model);
    }

それでおしまい。Index.cshtml にはトリックはありません。SearchForm を ActionResult インデックスに渡し、SearchViewModel をパラメーターとして渡します。

このソリューションが機能する理由

クリックしてソートまたはページングすると、WebGrid は次のような JavaScript を実行します。

$('#yourGrid').load('it pass the url used to display your current Page, and some paging or sorting parameters, but those are used by the WebGrid')

.load() メソッドを実行するため、リクエストは GET になり、Index GET ActionResult にヒットします。しかし、これは AJAX 呼び出しなので、マジック トリックは、Session に保存したパラメーターを使用してフィルターを再度実行します。

私が警告する固有の詳細は、デフォルトのグリッド動作に関するものです。GET Index ActionResult は、Session にフィルターがあるかどうかに関係なく、有効なグリッド結果を返す必要があります。

于 2013-03-20T15:18:26.167 に答える