【經驗分享】如何在FineUIMvc(ASP.NET MVC)視圖中綁定多個模型?


起因

這是知識星球內的一個網友提出的,按理說ASP.NET MVC中一個視圖只能綁定一個模型(Model),在視圖頂部標識如下:

@model IEnumerable<FineUICore.Examples.Areas.DataModel.Models.Student>

視圖中可以表格列可以使用RenderFieldFor來綁定:

@(F.Grid().IsFluid(true).CssClass("blockpanel").Title("表格").ShowHeader(true).ShowBorder(true).ID("Grid1").DataIDField("Id").DataTextField("Name")
    .Columns(
        F.RowNumberField(),
        F.RenderFieldFor(m => m.Name),
        F.RenderFieldFor(m => m.Gender).RendererFunction("renderGender").Width(80),
        F.RenderFieldFor(m => m.EntranceYear),
        F.RenderCheckFieldFor(m => m.AtSchool).RenderAsStaticField(true),
        F.RenderFieldFor(m => m.Major).RendererFunction("renderMajor").ExpandUnusedSpace(true),
        F.RenderFieldFor(m => m.Group).RendererFunction("renderGroup").Width(80),
        F.RenderFieldFor(m => m.EntranceDate)
    ).DataSource(Model)
)

 

使用 RenderFieldFor 而不是 RenderField 列類型,好處是不需要書寫每個列屬性,FineUIMvc會查看模型屬性的注解並自動完成屬性賦值工作:

 

作為對比,我們看下使用 RenderField 時視圖的標簽定義:

 

問題是,如果頁面上有多個表格需要綁定多個模型,該怎么辦呢?

探索之路

拋開表格的數據綁定不談,如果想向視圖中傳遞多個數據,可以把一個作為模型對象傳入,其他的作為ViewBag傳入。

但是這個常見解決方法不適用於表格和表格的 RenderFieldFor 列,因為這個列是和視圖模型密切相關的,在VS的智能提示幫助下,我們很容易發現這種關系:

 

可以看到傳入 RenderFieldFor 的 lambda表達式左側會被識別為模型的一部分,也就是說使用 RenderFieldFor 時模型類必須是 IEnumerable<> 泛型才對。

而一個視圖不可能傳入多個模型對象。

 

如果能將 模型和表格 綁定到一塊,類似 ASP.NET WebForms 中的用戶控件(UserControl),然后在主視圖中引入這些綁定好的塊豈不是很好?

其實ASP.NET MVC中有類似的解決方法,只不過不叫用戶控件,而稱為分部視圖(PartialView),下面我們就用分部視圖來實現上述功能。

1. 模型類(Student)上面已經介紹過了

2. 控制器,返回包含兩個對象元組對象

public IActionResult Index()
{
    var students = StudentHelper.GetSimpleStudentList();
    var model = new Tuple<IEnumerable<Student>, IEnumerable<Student>>(students.Where(m => m.AtSchool), students.Where(m => !m.AtSchool));
    return View(model);
}

3. 主視圖

@{
    var F = Html.F();
}

@using FineUICore.Examples.Areas.DataModel.Models;

@model Tuple<IEnumerable<Student>, IEnumerable<Student>>

@section body 
{

    @(Html.Partial("PartialGrid", Model.Item1, new ViewDataDictionary(ViewData) { { "__Title", "表格一(在校生)" } }))
    <br />
    @(Html.Partial("PartialGrid", Model.Item2, new ViewDataDictionary(ViewData) { { "__Title", "表格一(畢業生)" } }))
}

注意一下幾點:

3.1 模型類型是:Tuple<IEnumerable<Student>, IEnumerable<Student>>

3.2 在視圖中可以通過 Model.Item1 獲取元組中的第一個對象,相應的 Model.Item2 獲取第二個對象,從而省去了自定義類的麻煩

3.3 使用 Html.Partial 來渲染一個分部視圖,傳入三個參數:

----1. 分部視圖的名稱,會先在主視圖所在目錄中檢索,如果找不到會轉到 Shared 目錄檢索

----2. 傳入分部視圖的模型

----3. 額外的ViewData對象,如果需要引入多個分部視圖,可以在為每個分部視圖自定義顯示數據

 

4. 分部視圖(PartialGrid.cshtml)

@{
    var F = Html.F();
}

@model IEnumerable<FineUICore.Examples.Areas.DataModel.Models.Student>


@{
    var __Title = ViewData["__Title"].ToString();
}

@(F.Grid().IsFluid(true).CssClass("blockpanel").Title(__Title).ShowHeader(true).ShowBorder(true).DataIDField("Id").DataTextField("Name")
    .Columns(
        F.RowNumberField(),
        F.RenderFieldFor(m => m.Name),
        F.RenderFieldFor(m => m.Gender).RendererFunction("renderGender").Width(80),
        F.RenderFieldFor(m => m.EntranceYear),
        F.RenderCheckFieldFor(m => m.AtSchool).RenderAsStaticField(true),
        F.RenderFieldFor(m => m.Major).RendererFunction("renderMajor").ExpandUnusedSpace(true),
        F.RenderFieldFor(m => m.Group).RendererFunction("renderGroup").Width(80),
        F.RenderFieldFor(m => m.EntranceDate)
    ).DataSource(Model)
)

首先從 ViewData 獲取參數 __Title,然后在表格初始化時傳入 .Title(__Title)。

需要注意的一點,這里不能將Grid的ID屬性設為固定值,因為頁面上可能會多次渲染此分部視圖,比如下面的代碼:

@(F.Grid().ID("Grid1").IsFluid(true).CssClass("blockpanel").Title(__Title).

如果頁面上引入兩次本分部視圖,則頁面上會有兩個ID為 Grid1 的表格對象,這就搞錯了!

 

解決辦法有兩個:

1. 不設置 Grid 的 ID 屬性,這樣 FineUIMvc 會在頁面范圍內自動生成一個不重復的

2. 在主視圖調用 Html.Partial 時,傳入一個類似 __Prefix 的屬性,然后在分部視圖中為表格ID加上這個前綴,有沒有一種ASP.NET WebForms的感覺:

主視圖:

@(Html.Partial("PartialGrid", Model.Item1, new ViewDataDictionary(ViewData) { { "__Prefix", "Connector1" }, { "__Title", "表格一(在校生)" } }))
<br />
@(Html.Partial("PartialGrid", Model.Item2, new ViewDataDictionary(ViewData) { { "__Title", "Connector2" }, { "__Title", "表格一(畢業生)" } }))

分部視圖:

@(F.Grid().ID(ViewData["__Prefix"].ToString() + "_Grid1").IsFluid(true).CssClass("blockpanel").Title(__Title).

 

最終頁面的顯示效果:

 

 

 

小結

這篇文章講解了如何在ASP.NET MVC視圖中綁定多個模型,解決之道就是分部視圖(PartialView),分部視圖類似於ASP.NET WebForms中的用戶控件,而不同之處在於分部視圖不會給內部的控件ID加上所在的層次結構,因此如果一個頁面中多次引入同一個分部視圖就需要注意ID是否重復的問題了。

 

這個示例會更新到 FineUIMvc v5.3.0 版本中,查看 FineUIMvc 在線示例:http://mvc.fineui.com/

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM