[MVC] 自訂RadioButtonList

     MVC若要使用Radio Button,預設的HtmlHelper只有RadioButtonFor方法可以使用,這是單一個Radio Button,所以若要呈現5個按鈕就要呼叫5次,或使用迴圈巡覽資料集來叫用。而針對顯示的文字及Html也須另外撰寫。針對這種寫了會令人在維護時眼花瞭亂的程式,最好的方式還是寫了一個Helper來解決。


改善前的作法

    @foreach (var item in DataUtility.GetDatas())
                {
                    <label class="radio">
                        @Html.RadioButtonFor(model => model.ProductId, item.ProductId)
                        @Html.DisplayFor(model => item.ProductName)
                    </label>
                }


改善後的作法

1.針對上方的程式透過Helper的擴充,包成一個方法
/// <summary>
/// RadioButtonList for 資料集
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="helper"></param>
/// <param name="items">資料集</param>
/// <param name="dataValueField">值欄位</param>
/// <param name="dataTextField">顯示欄位</param>
/// <param name="expression"></param>
/// <param name="htmlAttributes"></param>
/// <param name="appendOptionLabel">是否增加預設選項 例:請選擇</param>
/// <param name="optionLabel">預設選項文字</param>
/// <param name="direction">顯示方向:垂直、水平</param>
/// <returns></returns>
public static MvcHtmlString RadioButtonListForList<T, TProperty>(this HtmlHelper<T> helper
    , IEnumerable items, string dataValueField, string dataTextField, Expression<Func<T, TProperty>> expression
    , object htmlAttributes = null, bool appendOptionLabel = false, string optionLabel = null
    , RepeatDirections direction = RepeatDirections.Horizontal)
{
    string name = BuildColumnNameFromModel(expression);
    var optionData = from object o in items
                        select new KeyValuePair<string, string>(Eval(o, dataTextField), Eval(o, dataValueField));
    string defaultSelectValue = helper.ViewData.Eval(name).ToString();
    return BuildRadioButtonList(helper, expression, name, defaultSelectValue, optionData, htmlAttributes, appendOptionLabel, optionLabel, direction);
}

2.同場加映列舉轉成RadioButtonList方法
/// <summary>
/// RadioButtonList for 列舉
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TProperty"></typeparam>
/// <param name="helper"></param>
/// <param name="expression"></param>
/// <param name="htmlAttributes"></param>
/// <param name="appendOptionLabel">是否增加預設選項 例:請選擇</param>
/// <param name="optionLabel">預設選項文字</param>
/// <param name="direction">顯示方向:垂直、水平</param>
/// <returns></returns>
public static MvcHtmlString RadioButtonListForEnum<T, TProperty>(this HtmlHelper<T> helper
, Expression<Func<T, TProperty>> expression
, object htmlAttributes = null, bool appendOptionLabel = false, string optionLabel = null
, RepeatDirections direction = RepeatDirections.Horizontal)
{
    string name = BuildColumnNameFromModel(expression);
    Enum defaultSelectValue = helper.ViewData.Eval(name) as Enum;
    IList<SelectListItem> selectList = EnumHelper.GetSelectList(typeof(TProperty), defaultSelectValue);
    List<KeyValuePair<string, string>> optionData = new List<KeyValuePair<string, string>>();
    foreach (var item in selectList)
    {
        optionData.Add(new KeyValuePair<string, string>(item.Text, item.Value));
    }
    return BuildRadioButtonList(helper, expression, name, Convert.ToInt32(defaultSelectValue).ToString(), optionData, htmlAttributes, appendOptionLabel, optionLabel, direction);
}
如何使用方法
透過包裝後的方法,在使用上只要傳入資料集或列舉值就可回傳RadioButtoList可使用

<div class="form-group">
    @Html.LabelFor(model => model.ProductId, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.RadioButtonListForList(DataUtility.GetDatas(), "ProductId", "ProductName", model => model.ProductId, direction: RepeatDirections.Vertical)
            </div>
</div>

<div class="form-group">
    @Html.LabelFor(model => model.Direction, htmlAttributes: new { @class = "control-label col-md-2" })
    <div class="col-md-10">
        @Html.RadioButtonListForEnum(model=>model.Direction)
     </div>
</div>

完整範例
https://github.com/kimx/RadioButtonListLab/

這個網誌中的熱門文章

[TFS] 分支與合併

[.NET Core] 將專案發行至IIS