我正在嘗試創建(或者更好的發現)一個自定義html擴展方法,它與ListBoxFor類似的莊園工作,但呈現一組複選框而不是選擇多個。創建一個自定義html擴展,它將像ListBoxFor一樣工作,但輸出複選框?
這樣做的最好方法是什麼?我很好奇ListBoxFor方法是如何工作的,它只傳遞一個表達式和一個SelectListItems的枚舉,它們只有默認選項。它沒有通過模型,所以它怎麼知道什麼時候選擇正確的項目(它似乎能夠做到這一點)?另外,它如何根據匿名對象編寫html屬性?
我正在嘗試創建(或者更好的發現)一個自定義html擴展方法,它與ListBoxFor類似的莊園工作,但呈現一組複選框而不是選擇多個。創建一個自定義html擴展,它將像ListBoxFor一樣工作,但輸出複選框?
這樣做的最好方法是什麼?我很好奇ListBoxFor方法是如何工作的,它只傳遞一個表達式和一個SelectListItems的枚舉,它們只有默認選項。它沒有通過模型,所以它怎麼知道什麼時候選擇正確的項目(它似乎能夠做到這一點)?另外,它如何根據匿名對象編寫html屬性?
你還沒有提供任何細節和你想要達到的具體例子。您目前尚未提供您嘗試過的任何源代碼,以解決您遇到的問題。下次你在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;
}
}
對不起,我的問題太模糊了,但感謝你的回答,我已經從中學到了很多東西。特別是我不知道TagBuilder和htmlHelper.ViewData.Eval。 – zod 2012-01-03 16:10:14
@zod,你沒有看過ASP.NET MVC源代碼嗎?我會建議你這樣做,以瞭解標準助手是如何實現的。它將使您能夠更好地理解框架,並使其更容易實現自定義幫助程序。 – 2012-01-03 16:12:22
這會爲每個複選框生成相同的ID,我認爲這是錯誤的,所以我刪除了一行(不要以爲他們需要IDS)。它也不使用html屬性,但我幾乎不需要它,所以刪除它。否則它是優秀的(我把整個東西包裝在一個div中,給了一個類(硬編碼)(也許我應該給這個id),並把每個複選框和文本對放入一個標籤標籤中)。非常感謝。 – zod 2012-01-03 16:12:53