之前为F.Grid做了扩展,自动生成了三个按钮,并和本身的window控件联动弹出编辑窗口。编辑窗口以F.Form为主,这次我把F.Form控件增加扩展,主要用于绑定数据,拿取数据,自动验证并提交,以及简单的布局。
导言
之前为F.Grid做了扩展,自动生成了三个按钮,并和本身的window控件联动弹出编辑窗口。编辑窗口以F.Form为主,这次我把F.Form控件增加扩展,主要用于绑定数据,拿取数据,自动验证并提交,以及简单的布局。
1. 为F.Form绑定数据(字段赋值)
FineUICore本身有model和表单的对照demo,就是MVC的传统写法,通过用模型绑定控件,但是我项目里的Model是没有特性的,就是传统的类
/// <summary>
/// ID
/// </summary>
public int Id { get; set; }
所以如果为表单控件赋值就要写成 ID.Text = ms.XXX;,如果能实现自动匹配映射是很减少工作量的。
首先要在js为F.Form扩展 setValue 和 getValue 方法,将Model的Json格式绑定到表单的各个控件,然后在取值返回Json格式,传到后台(.cs)再转为Model进行保存操作。
这种模式绑定和读取数据很像Grid的操作,Grid中有两个关键属性,DataIDField 和 DataField 属性,一个是标识字段名,一个是绑定的字段名,如果我为F.Form()(.cshtml)扩展这两个属性
F.Form().Width(900).LabelWidth(100).BodyPadding(5).EnableCollapse(true)
.ID("Form1").Title("表单1")
.DataIDField("Id")//数据标识字段名
表单项
F.TextBox().Label("姓名").DataField("Name")//字段名称
F.DropDownList().Label("性别").DataField("Gender")//字段名称
那么js怎么获取到我绑定的 Id,Name,Gender 呢,这里用到了F自带的为HTML标签扩展的属性 Attribute ,该属性在 ControlBaseExtension 下,所有控件继承,该方法直接为HTML标签生成一个属性,js通过 attr 很容易就拿到了,把这个属性拿到,然后直接和JSON匹配就行了。
点击F.Form(),按F12,
//
// 摘要:
// 表单面板控件扩展
public FormExtension Form();
FineUIEx类中扩展增加方法 DataIDField
/// <summary>
/// 数据标识字段名
/// </summary>
/// <param name="f">控件实例</param>
/// <param name="DataIDField">主键字段</param>
/// <returns></returns>
public static FormExtension DataIDField(this FormExtension f, string DataIDField)
{
//为Form增加属性
f.Attribute("DataID", DataIDField);
return f;
}
字段的DataField,在Form的FormRow.Items中参数为IControlBaseExtension[]
//
// 摘要:
// 子控件集合
//
// 参数:
// extensions:
public FormRowExtension Items(params IControlBaseExtension[] extensions);
如果将DataField扩展到IControlBaseExtension中,会有问题,所有控件都继承IControlBaseExtension,但是我只需要输入的控件 比如 TextBox 或 DropDownList ,又不能每个控件都单独扩展,所以找到所有文本输入控件都继承的类 FieldExtension
//
// 摘要:
// 表单字段基类扩展
//
// 类型参数:
// T:
//
// TExtension:
public abstract class FieldExtension
这里还要注意,DataField 方法返回的是当前实例,即谁继承FieldExtension就返回谁(比如F.DropDownList()有DataSource方法而F.TextBox()没有,如果返回统一类型将无法继承该控件实例的单独属性)。
FineUICore自己就解决了这个问题,比如 Label 方法,就在FieldExtension下,所有表单控件继承,
//
// 摘要:
// 标签文本
//
// 参数:
// param:
public TExtension Label(string param);
注意该方法的返回类型是TExtension,泛型,哪来的呢,上层传过来的,比如 DropDownList控件,
//
// 摘要:
// 下拉列表控件扩展
public class DropDownListExtension : TextFieldExtension<DropDownList, DropDownListExtension>
看<DropDownList, DropDownListExtension>,他已经把自己的类型,通过T参数传到他的继承类中了,所以Label后还可以返回当前实例,落在表单的DataField中,应该这么写
/// <summary>
/// 绑定数据字段
/// </summary>
/// <typeparam name="T"></typeparam>
/// <typeparam name="TExtension"></typeparam>
/// <param name="f"></param>
/// <param name="datafield"></param>
/// <returns></returns>
public static TExtension DataField<T, TExtension>(this FieldExtension<T, TExtension> f,string datafield)
where T : Field
where TExtension : FieldExtension<T, TExtension>
{
f.Attribute("data", datafield);
return (TExtension)f;
}
到此对.cshtml的扩展就结束了,下面是js的扩展,主要是用attr方法,查找 DataID 和 data 属性
if (F.Form) {
$.extend(F.Form.prototype, {
//得到数据 (是否验证)
getdata: function (isv) {
var t = this;
var data = t.initData || {};
if (isv) {
if (!F.validateForm(t.id, '_self', false, false)) {
return false;
}
}
var datael = $(t.el).find(".f-field[data]");
//循环表单项
$.each(datael, function (i, v) {
var id = $(v).attr("id");
var d = $(v).attr("data").replace("Data_", "");
//如果存在data属性
if (d) {
//取值
data[d] = F.ui[id].getValue();
//注意日期控件 取text,否则会提取出时间戳
if (F.ui[id].type == 'datepicker') {
data[d] = F.ui[id].getText();
}
}
})
//返回json
return data;
},
//设置数据
setdata: function (data) {
var t = this;
t.initData = data;
var datael = $(t.el).find(".f-field[data]");
//绑定dataid
var dataid = $(t.el).attr("DataID");
if (dataid && dataid != '') {
F.ui[t.id].beforDataID = F.ui[t.id].DataID;
F.ui[t.id].DataID = data[dataid];
};
//循环表单项
$.each(datael, function (i, v) {
var id = $(v).attr("id");
var d = $(v).attr("data").replace("Data_", "");
if (d && (typeof data[d]) != 'undefined') {
//找到data属性,并赋值
F.ui[id].setValue(data[d]);
}
})
}
});
}
扩展完成,使用时可以直接这样
表单控件(.cshtml)
F.Form().Width(900).LabelWidth(100).BodyPadding(5).EnableCollapse(true)
.ID("Form1").Title("表单1")
.DataIDField("Id")
表单项(.cshtml)
F.TextBox().Label("姓名").DataField("Name").Requ(true),
F.DropDownList().Label("性别").DataField("Gend.Required(true)
.Items(
F.ListItem().Text("男").Value("1"),
F.ListItem().Text("女").Value("0")
),
F.TextBox().Label("入学年份").DataField("EntranceYear"),
F.DropDownList().Label("是否在校").DataField("AtSchool")
.Items(
F.ListItem().Text("是").Value("1"),
F.ListItem().Text("否").Value("0")
),
F.TextBox().Label("所学专业").DataField("Major"),
F.TextBox().Label("分组").DataField("Group")
js(.cshtml)
F.ready(function () {
F.ui['Form1'].setdata(@Html.Raw(ViewBag.data));
})
后台.cs
public ActionResult Index()
{
MsStudent ms1 = new MsStudent();
//得到实体数据
ms1 = studentHelper.GetMsById(Convert.ToInt32(101));
ViewBag.data = JObject.FromObject(ms1).ToString();
return View();
}
具体效果,可以在FineUIMVC扩展中查看。