2012-01-03 45 views
1

我正在嘗試創建(或者更好的發現)一個自定義html擴展方法,它與ListBoxFor類似的莊園工作,但呈現一組複選框而不是選擇多個。創建一個自定義html擴展,它將像ListBoxFor一樣工作,但輸出複選框?

這樣做的最好方法是什麼?我很好奇ListBoxFor方法是如何工作的,它只傳遞一個表達式和一個SelectListItems的枚舉,它們只有默認選項。它沒有通過模型,所以它怎麼知道什麼時候選擇正確的項目(它似乎能夠做到這一點)?另外,它如何根據匿名對象編寫html屬性?

回答

2

你還沒有提供任何細節和你想要達到的具體例子。您目前尚未提供您嘗試過的任何源代碼,以解決您遇到的問題。下次你在StackOverflow上提出一個問題時,請這樣做,以便讓你的問題更有意義並專注於一個特定的問題。

無論如何,這裏是一個例子。讓我們假設你已經定義的視圖模型:

public class MyViewModel 
{ 
    public IEnumerable<string> SelectedValues { get; set; } 
    public IEnumerable<SelectListItem> Values { get; set; } 
} 

和控制器將填充這一觀點與價值模型,並希望在POST操作獲取在視圖中選擇的值:

public class HomeController : Controller 
{ 
    public ActionResult Index() 
    { 
     var model = new MyViewModel 
     { 
      SelectedValues = new[] { "1", "3" }, 
      Values = new[] 
      { 
       new SelectListItem { Value = "1", Text = "item 1" }, 
       new SelectListItem { Value = "2", Text = "item 2" }, 
       new SelectListItem { Value = "3", Text = "item 3" }, 
      } 
     }; 
     return View(model); 
    } 

    [HttpPost] 
    public ActionResult Index(MyViewModel model) 
    { 
     // model.SelectedValues will contain the ids of items that were checked 
     // in the checkbox list 
    } 
} 

和那麼一個看法:

@model MyViewModel 

@using (Html.BeginForm()) 
{ 
    @Html.CheckBoxListFor(x => x.SelectedValues, Model.Values, null) 
    <button type="submit">OK</button> 
} 

好吧,到目前爲止好。最後一部分是嘗試實施這個幫助器CheckBoxListFor。顯然,根據你的具體要求和背景,可能有很多可能的方法來做到這一點(請參閱我在答案開頭的評論)。所以這裏只是一些可以讓你開始的示例實現:

public static class HtmlExtnsions 
{ 
    public static IHtmlString CheckBoxListFor<TModel, TProperty>(
     this HtmlHelper<TModel> htmlHelper, 
     Expression<Func<TModel, TProperty>> expression, 
     IEnumerable<SelectListItem> selectList, 
     object htmlAttributes 
    ) 
    { 
     var name = ExpressionHelper.GetExpressionText(expression); 
     string fullHtmlFieldName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name); 
     var values = GetModelStateValue(htmlHelper.ViewData, fullHtmlFieldName, typeof(string[])); 
     if (values == null) 
     { 
      values = htmlHelper.ViewData.Eval(fullHtmlFieldName); 
     } 

     if (values != null) 
     { 
      var collection = 
       from object value in values as IEnumerable 
       select Convert.ToString(value, CultureInfo.CurrentCulture); 
      var hashSet = new HashSet<string>(collection, StringComparer.OrdinalIgnoreCase); 
      var list = new List<SelectListItem>(); 
      foreach (var item in selectList) 
      { 
       item.Selected = ((item.Value != null) ? hashSet.Contains(item.Value) : hashSet.Contains(item.Text)); 
       list.Add(item); 
      } 
      selectList = list; 
     } 

     var sb = new StringBuilder(); 
     foreach (var item in selectList) 
     { 
      var checkbox = new TagBuilder("input"); 
      checkbox.Attributes["type"] = "checkbox"; 
      checkbox.Attributes["name"] = fullHtmlFieldName; 
      checkbox.Attributes["value"] = item.Value; 
      checkbox.GenerateId(fullHtmlFieldName); 
      if (item.Selected) 
      { 
       checkbox.Attributes["checked"] = "checked"; 
      } 
      sb.Append(checkbox.ToString(TagRenderMode.SelfClosing)); 
      sb.Append(item.Value); 
     } 

     return new HtmlString(sb.ToString()); 
    } 

    private static object GetModelStateValue(ViewDataDictionary viewData, string key, Type destinationType) 
    { 
     ModelState modelState; 
     if (viewData.ModelState.TryGetValue(key, out modelState) && modelState.Value != null) 
     { 
      return modelState.Value.ConvertTo(destinationType, null); 
     } 
     return null; 
    } 
} 
+1

對不起,我的問題太模糊了,但感謝你的回答,我已經從中學到了很多東西。特別是我不知道TagBuilder和htmlHelper.ViewData.Eval。 – zod 2012-01-03 16:10:14

+0

@zod,你沒有看過ASP.NET MVC源代碼嗎?我會建議你這樣做,以瞭解標準助手是如何實現的。它將使您能夠更好地理解框架,並使其更容易實現自定義幫助程序。 – 2012-01-03 16:12:22

+0

這會爲每個複選框生成相同的ID,我認爲這是錯誤的,所以我刪除了一行(不要以爲他們需要IDS)。它也不使用html屬性,但我幾乎不需要它,所以刪除它。否則它是優秀的(我把整個東西包裝在一個div中,給了一個類(硬編碼)(也許我應該給這個id),並把每個複選框和文本對放入一個標籤標籤中)。非常感謝。 – zod 2012-01-03 16:12:53

相關問題