.NET MVC里面自动绑定form表单功能(如:@Html.TextBox("Name")、@Html.Hidden("hide"),名称会自动与后台就行绑定ViewBag.Name,ViewBag,hide)很实用,但是感觉不足的就是@Html.CheckBox("check")和@Html.RadioButton("radio","1"),这两个表单只能单个进行绑定,当出现多个绑定进行选中时,用起来就相对不太方便,如下图
想要通过集合直接绑定生成需要的多个checkbox和radiobutton,并且部分处于选中状态,还好.NET的扩展方法为我们提供了方便。扩展方法就不用多说了,就是在静态类中,建立静态方法,并且第一个参数是 (this [要扩展的对象] name),
比如,你要给string类型扩展一个方法,要求当string长度超过10的时候只要截取前十个字符,当长度少于10的时候返回原字符串你可以这样:
namespace System
{
public static class StringExtension
{
public static string SubTen(this string sourceStr) {
if(!string.IsNullOrEmpty(sourceStr)&&sourceStr.Length>10){
return sourceStr.Substring(0,10);
}
return sourceStr;
}
}
}</span>
调用的时候如下所示: string SS = "AASSSSSSSSSSSSSS";
var SSS = SS.SubTen();
这样当字符串长度大于10 的时候就会取出前十个字符。
好了,扩展方法就说到这里,现在进入正题,对HtmlHelper要扩展四个方法,分别是生成checkbox集合,checkbox单个,radio集合和radio单个。
方法如下,因为checkbox和radio只是type类型不同,因此,他们可以用同样的方法,只是传值的时候把类型传入进行判断就可以了。
private static IDictionary<string, object> CopyAll(this IDictionary<string, object> dicSor)
{
Dictionary<string, object> dicDst = new Dictionary<string, object>();
foreach (var item in dicSor)
{
dicDst.Add(item.Key, item.Value);
}
return dicDst;
}
这里的dictionary的扩展是方便循环的时候使用。 /// <summary>
/// 扩展checkbox和radio
/// </summary>
/// <param name="targtname">后台的取值</param>
/// <param name="itype">标签类型</param>
/// <param name="name">标签值name或者取后台值用到</param>
/// <param name="selectList">传入的集合</param>
/// <param name="htmlAttributes">Html标签属性</param>
/// <returns></returns>
private static MvcHtmlString RadioOrCheckBox(object targtname, string itype, string name, IEnumerable<SelectListItem> selectList, object htmlAttributes)
{
//不存在绑定值则返回空
if (string.IsNullOrEmpty(name) || (targtname == null && selectList == null))
{
return MvcHtmlString.Create("");
}
//if (htmlHelper.ViewData.ContainsKey(name)) {
// name = htmlHelper.ViewData[name].ToString();
//}
string selectValues = "";
Object selectedValues = null;
HashSet<string> ckSet = new HashSet<string>();//用于存储选定值,不添加重复项
List<SelectListItem> listSelectListItem = new List<SelectListItem>(); //这里可以不新建对象直接用selectList,这样下面画-----横线的代码也可以省略
if (targtname != null) //后台取值赋值
{
// selectList = new List<SelectListItem>();//---------
if (targtname.GetType() != typeof(SelectList)) //后台传入ViewBag.AAA=new SelectList()类型
{
return MvcHtmlString.Create("");
}
SelectList slItemlist = targtname as SelectList;
selectedValues = slItemlist.SelectedValue ?? ""; //要选中的值
if (selectedValues != null)
{
selectValues = selectedValues.ToString();
string[] tempStr = selectValues.Split(','); //多个选中用逗号隔开
//Array.IndexOf(tempStr, "");
ckSet = new HashSet<string>(tempStr);
}
foreach (var item in slItemlist)
{
if (ckSet.Contains(item.Value))
{
item.Selected = true; //选中值设为true
}
listSelectListItem.Add(item);
}
}
//验证绑定的对象
if (listSelectListItem.Count <= 0 && selectList != null && selectList.Count() > 0)//--------------
{
listSelectListItem.AddRange(selectList);//--------
}
string id = string.Empty; //checkbox一般不带id,这几行代码其实没用
IDictionary<string, object> htmlAttributesdic = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
if (htmlAttributesdic.ContainsKey("id"))
{
id = htmlAttributesdic["id"].ToString();
htmlAttributesdic.Remove("id");
}
htmlAttributesdic.Add("type", itype);//生成的类型,是checkbox或者是radio
htmlAttributesdic.Add("name", name);
StringBuilder sbHtml = new StringBuilder();
foreach (SelectListItem selectItem in listSelectListItem)
{
IDictionary<string, object> newDicAttributes = htmlAttributesdic.CopyAll();
newDicAttributes.Add("value", selectItem.Value);
if (selectItem.Selected) //为true则处于选中状态
{
newDicAttributes.Add("checked", "checked");
}
TagBuilder tagBuilder = new TagBuilder("input");//新建input表单
tagBuilder.MergeAttributes<string, object>(newDicAttributes); //添加表单属性
string inputAllHtml = tagBuilder.ToString(TagRenderMode.SelfClosing); //TagRenderMode枚举,自关闭类型如:<input />
string containerFormat = @"<label> {0} {1}</label>"; //外层套上label可以点击文字的时候选中按钮,如果想要水平垂直居中最后在加上<P></P>标签
sbHtml.AppendFormat(containerFormat,
inputAllHtml, selectItem.Text);
}
return MvcHtmlString.Create(sbHtml.ToString());
}
因为这是绑定集合数据,因此targtname和selectList参数不能同时为空,默认是以targtname绑定的数据优先,当targtname存在且类型正确的时候,绑定targtname中的数据,当targtname取后台值为null的时候再判断取selectList中的值,上面的后台取值其实可以优化更通用一点,只是感觉没那么必要了,自己定的一个约定知道赋值取值一般不会出错。其他的就不多介绍了,注释里面很详细了。
真正的扩展到了,如下:
/// <summary>
/// checkbox集合扩展
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="name">标签名称</param>
/// <param name="selectList">items</param>
/// <param name="htmlAttributes">属性html</param>
/// <returns></returns>
public static MvcHtmlString CheckBoxList(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList, object htmlAttributes)
{
var targtname = htmlHelper.ViewData[name];//取后台数据
return RadioOrCheckBox(targtname, "checkbox", name, selectList, htmlAttributes);
}
/// <summary>
/// radio集合扩展
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="name">name属性</param>
/// <param name="selectList">item属性</param>
/// <param name="htmlAttributes">额外属性</param>
/// <returns></returns>
public static MvcHtmlString RadioButtonList(this HtmlHelper htmlHelper, string name, IEnumerable<SelectListItem> selectList, object htmlAttributes)
{
var targtname = htmlHelper.ViewData[name];//取后台数据
return RadioOrCheckBox(targtname, "radio", name, selectList, htmlAttributes);
}
这样,放到静态类的静态方法就可以正常使用了,注意这个命名空间,最好用System.Web.Mvc.Html这样与其他的扩展方法命名空间一致,那样省去我们在页面还要单独引用命名空间。
namespace System.Web.Mvc.Html
{
public static class InputExtension
{
}
}
在html页面中使用方式如下:
@Html.CheckBoxList("Drop",null, new {@class = "tclass", @style = "" }) <br />
@Html.RadioButtonList("Drop",null, new {@class = "tclass", @style = "" })<br/>
接下来扩展单个标签的radio和checkbox标签,方便的在循环的时候使用,少了对是否选中的判断,只要value值与是否选中的值一致,那么他就处于选中状态,不一致则不选中,不用再判断if(){}else if(){},
代码如下:
/// <summary>
/// 单标签为了在循环的时候使用方便
/// </summary>
/// <param name="itype">标签类型</param>
/// <param name="name">标签name属性</param>
/// <param name="value">标签value值</param>
/// <param name="showText">radio或者checkbox要显示的名字</param>
/// <param name="htmlAttributes">标签的其他属性</param>
/// <param name="selectValue">选中的值</param>
/// <returns></returns>
private static MvcHtmlString RadioOrCheckBoxItem(string itype,string name, string value, string showText, object htmlAttributes, string selectValue = "")
{
//生成<input type='radio' name ='name' value='value'> name和value不能为空
if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(value))
{
return MvcHtmlString.Create("");
}
StringBuilder sbHtml = new StringBuilder();
IDictionary<string, object> htmlAttributesdic = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
htmlAttributesdic.Add("type", itype); //标签类型radio或者checkbox
htmlAttributesdic.Add("value", value);
htmlAttributesdic.Add("name", name);
var dd = string.Compare(value, selectValue, true);
if (value.Equals(selectValue, StringComparison.OrdinalIgnoreCase)) //这里判断当value和selectValue一致,则处于选中状态
{
htmlAttributesdic.Add("checked", "checked");
}
TagBuilder tagBuilder = new TagBuilder("input");
tagBuilder.MergeAttributes<string, object>(htmlAttributesdic);
string inputAllHtml = tagBuilder.ToString(TagRenderMode.SelfClosing);
string containerFormat = @"<label> {0} {1}</label>";
sbHtml.AppendFormat(containerFormat,
inputAllHtml, showText);
return MvcHtmlString.Create(sbHtml.ToString());
}
这个就不解释了,和上面那个道理一样。
/// <summary>
/// 单个checkbox扩展
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="name">name属性</param>
/// <param name="value">值</param>
/// <param name="showText">要显示的文本</param>
/// <param name="htmlAttributes">额外属性</param>
/// <param name="selectValue">选中的值</param>
/// <returns></returns>
public static MvcHtmlString CheckBoxItem(this HtmlHelper htmlHelper, string name, string value, string showText, object htmlAttributes, string selectValue = "")
{
return RadioOrCheckBoxItem("checkbox",name, value, showText, htmlAttributes, selectValue);
}
/// <summary>
/// radio单个按钮
/// </summary>
/// <param name="htmlHelper"></param>
/// <param name="name">标签name</param>
/// <param name="value">radio值</param>
/// <param name="showText">显示的文本</param>
/// <param name="htmlAttributes">额外属性</param>
/// <param name="selectValue">选中的值</param>
/// <returns></returns>
public static MvcHtmlString RadioButtonItem(this HtmlHelper htmlHelper, string name, string value, string showText, object htmlAttributes, string selectValue = "")
{
return RadioOrCheckBoxItem("radio", name, value, showText, htmlAttributes, selectValue);
}
好了几个扩展方法写完了,下面就到了用的时候了:
MVC控制器代码:
public ActionResult Index()
{
Dictionary<string, object> dic = new Dictionary<string, object>();
dic.Add("1", "字典一");
dic.Add("2", "字典二");
dic.Add("3", "字典三");
ViewBag.DIC = new SelectList(dic, "key", "value", "3,2");
List<DropList> listdrop = new List<DropList>(){
new DropList(){dname="自定义集合一", dvalue="one", dother="dropvalueOne"},
new DropList(){dname="自定义集合二", dvalue="two", dother="dropvalueTwo"},
new DropList(){dname="自定义集合三", dvalue="three", dother="dropvalueThree"}
};
ViewBag.Drop = new SelectList(listdrop, "dvalue", "dname", "two");
List<SelectListItem> ieitem = new List<SelectListItem>(){
new SelectListItem(){ Selected=true, Text="不存在一", Value="sdfg"},
new SelectListItem(){ Selected=false, Text="不存在二", Value="ryhfgh"},
new SelectListItem(){ Selected=true, Text="不存在三", Value="yuioi"}
};
ViewBag.RRR = ieitem;
return View()
}
MVC视图代码测试radio和checkbox集合:
<fieldset>
<legend>这是测试集合</legend><br/>
<label>后台不存在ViewBag.AAAA则取 ViewBag.RRR:</label>
@Html.CheckBoxList("AAAA", ViewBag.RRR as IEnumerable<SelectListItem>,new{ style = "" })<br /><br />
<label>后台存在ViewBag.DIC:</label>
@Html.CheckBoxList("DIC", null, new { @class = "tclass", @style = "" }) <br /><br />
<label>后台存在ViewBag.Drop:</label>
@Html.RadioButtonList("Drop", null, new { @class = "tclass", @style = "" })<br /><br />
</fieldset>
生成结果如下图所示:
MVC视图单个radio和checkbox,如下:
<fieldset>
<legend>这是测试单个</legend><br/>
<label>radio单个:</label>
@Html.RadioButtonItem("AAA", "45", "测试radio1", new { }, "415")
@Html.RadioButtonItem("AAA", "425", "测试radio2", new { }, "425")<br/><br/>
<label>checkbox单个:</label>
@Html.CheckBoxItem("BBBB", "3", "测试checkbox", new { }, "34")
@Html.CheckBoxItem("BBBB", "34", "测试checkbox", new { }, "34")
@Html.CheckBoxItem("BBBB", "35", "测试checkbox", new { }, "35")
</fieldset>
生成的结果如下图所示:
好了,写完了,希望对大家有所帮助,有什么不对或者需要优化的地方还请大家批评指出,我会尽快改正,谢谢!