[.NET MVC]自訂檢視及輯範本

在MVC的View頁面中,不管是由Scafford產生或自行撰寫時,我們常會用到輔助方法的方式來撰寫,而在強型別的輔助方法中,更是直接參考Model中的Metadata來產生對應的Html tag及attribute, 讓我們對Model各欄位的考量及思考能夠統一的制定在Model類別,達到關注點分離的效果。

在MVC的View頁面中,不管是由Scafford產生或自行撰寫時,我們常會用到輔助方法的方式來撰寫,而在強型別的輔助方法中,更是直接參考Model中的Metadata來產生對應的Html tag及attribute, 讓我們對Model各欄位的考量及思考能夠統一的制定在Model類別,達到關注點分離的效果。


<div class="editor-label">
    @Html.LabelFor(model => model.Email)
</div>
<div class="editor-field">
    @Html.EditorFor(model => model.Email)
    @Html.ValidationMessageFor(model => model.Email)
</div>
 

如上方的LabelFor、EditorFor其實都是透過參考Model的Metadata來判斷該如何產生對應的Html Tag ,如果在client檢示HTML的話,依照Default template可能產生如下結果:

通常一般預設的輸出已經符合我們使用, 但如果想要更客製化,不管是要新增一個輸出Html範本或者修改預設的範本,在MVC中均可以支援。

Display Template

/Views/{Controller}/DisplayTemplates

/Views/Shared/DisplayTemplates

Editor Template

/Views/{Controller}/EditorTemplates

/Views/Shared/ EditorTemplates

如上表,如果想自訂LabelFor、EditorFor輸入的樣式, 可以藉由在View中建立cshtml檔並擺放在對應位置,DisplayFor擺放在DisplayTemplates目錄下,EditorFor則是EditorTemplates; 如果該自訂的範本只想給單一支Controller使用,則放置在該Controller下,如果是所有View頁面均能使用的情況,則放置於Shared目錄下。

而在檔案的命名上,如果想直接覆蓋掉原有的預設Template,可以直接用DataType的名稱,或者也可以建立一個新的template, 在Model上在透過UIHint屬性來加以套用。而在Model的各property在判斷要捉取的範本時,其順序是1. UIHint中指定的範本 2. DataType attribute (如 [DataType(DataType.Password)]) 3. 該Property本身的DataType (不含命名空間的.NET型別名稱)

實際覆寫一個檢視範本

撰寫此種view template方式其實大同小異,而這邊示範的是檢視的寫法;基本上我認為編輯範本的寫法要考量的比較多,尤其在覆寫預設範本時要參考原本的寫法,或者可能導致自已覆寫的版本對某些Metadata或attribute不支援。

這邊先假設我們想針對DislayFor作修改,讓DataType.Password這樣的欄位在顥示時直接以#號取代表原本的字符。

Model:


public class Member
    {
        [DisplayName("會員帳號")]
        [DataType(DataType.EmailAddress)]
        public string Email { get; set; }

        [DisplayName("會員密碼")]
        [DataType(DataType.Password)]
        public string Password { get; set; }
    }

View:


@model IEnumerable<MVC4Lab.Models.Member>
<table>
    <tr>
        <th>
            @Html.DisplayNameFor(model => model.Email)
        </th>
        <th>
            @Html.DisplayNameFor(model => model.Password)
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Email)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Password)
        </td>
    </tr>
}

輸出:

預設的DataType.Password在DisplayFor時如同一般字串顯示,雖然我們不可能將未加密的密碼直接就儲存在DB中,這邊我們還是可以用自訂方式,讓View在顯示時將這類型的資料在次遮蔽。

由於並不限定單一的Controller使用, 所以放置在Views/Shared/DisplayTemplate下,並直接以Password.csthml來加以命名

Password.cshtml


@model System.String
@{
    var Password = Model;
    var DisplayCode = String.Empty;
    Password.ToCharArray().ToList().ForEach(c =>DisplayCode += "#");
    
}
<div class="display-field">
    @DisplayCode  
</div>
重新檢示原View 頁面:

如此, 在Password.cshtml中提供了完全的彈性,你想怎麼玩就則麼玩, 如果MVC在View中提供了非常高的可延申性,即便遇到在特別的專案,相信都能自訂成你要的樣式。