DymWebForm.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Drawing;
  4. using System.Linq;
  5. using System.Reflection;
  6. using System.Web;
  7. using System.Web.UI;
  8. using System.Web.UI.WebControls;
  9. namespace DymWebForm.Aspx
  10. {
  11. public class DymWebForm<T>
  12. {
  13. private static readonly Type Type = typeof(T);
  14. private static readonly FormField<T>[] AllField;
  15. private static readonly FormField<T> PkField;
  16. static DymWebForm()
  17. {
  18. AllField = FormFieldFactory<T>.GetFormFields();
  19. PkField = AllField.FirstOrDefault(p => p.IsPK);
  20. if (PkField == null)
  21. throw new ArgumentException("Must define PK");
  22. }
  23. private static void ProcTdFK(Func<Type, object[], object[]> fkQuery, List<FieldFK<T>> lstFKs)
  24. {
  25. lstFKs
  26. .GroupBy(p => p.Field.FKParentType)
  27. .ToDictionary(p => p.Key, p => p.ToArray())
  28. .ForEach(p =>
  29. {
  30. var arrFKID = p.Value
  31. .Select(q => q.FKVal)
  32. .Distinct()
  33. .ToArray();
  34. var dicFKobj = fkQuery(p.Key, arrFKID)
  35. .ToDictionary(
  36. FormFieldFactoryProxy.GetPKValue
  37. , q => q
  38. );
  39. p.Value.ForEach(q =>
  40. {
  41. q.Td.Controls.Add(new Literal() { Text = q.FKVal.ToDisplayString() });
  42. q.Td.Controls.Add(new Literal() { Text = ": " });
  43. object parVal = null;
  44. var found = false;
  45. if (dicFKobj.ContainsKey(q.FKVal))
  46. {
  47. found = true;
  48. var par = dicFKobj[q.FKVal];
  49. parVal = FormFieldFactoryProxy.GetFKValue(par);
  50. }
  51. if (found)
  52. {
  53. q.Td.Controls.AddEx(new Label() { Text = parVal.ToDisplayString() ?? "NULL", ForeColor = Color.Blue })
  54. .Font.Italic = (parVal == null);
  55. }
  56. else
  57. {
  58. q.Td.Controls.Add(new Label() { Text = "无对应", ForeColor = Color.Red });
  59. }
  60. });
  61. });
  62. }
  63. private static Table RenderDetailsInternal(WebControl container, T entity, Func<Type, object[], object[]> fkQuery, string[] skipFields = null)
  64. {
  65. skipFields = skipFields ?? new string[] { };
  66. var arrFieldsToDisplay = AllField
  67. .Where(p => skipFields.Contains(p.FieldName) == false)
  68. .ToArray();
  69. //init
  70. var tbl = new Table();
  71. container.Controls.Add(tbl);
  72. tbl.Attributes.Add("border", "1");
  73. tbl.Style[HtmlTextWriterStyle.BorderCollapse] = "Collapse";
  74. tbl.CellSpacing = 1;
  75. tbl.CellPadding = 2;
  76. List<FieldFK<T>> lstFKs = new List<FieldFK<T>>();
  77. //generate fields of form
  78. foreach (var field in arrFieldsToDisplay)
  79. {
  80. var tr = new TableRow();
  81. tbl.Rows.Add(tr);
  82. var objVal = field.GetValue(entity);
  83. //field name
  84. tr.Cells.Add(new TableCell() { Text = field.DisplayName + ":" });
  85. //field control
  86. var td = new TableCell();
  87. tr.Cells.Add(td);
  88. td.VisualText(objVal.ToDisplayString());
  89. //fk
  90. if (field.IsFK && objVal != null)
  91. {
  92. lstFKs.Add(new FieldFK<T> { Field = field, Td = td, FKVal = objVal });
  93. }
  94. }
  95. if (fkQuery != null)
  96. {
  97. ProcTdFK(fkQuery, lstFKs);
  98. }
  99. return tbl;
  100. }
  101. /// <summary>
  102. ///
  103. /// </summary>
  104. /// <param name="container">容器, 要求已经添加到Page</param>
  105. /// <param name="dataSource">数据源</param>
  106. /// <param name="arrSkipFields">跳过的字段(如密码)</param>
  107. /// <param name="fkQuery">外键查询回调</param>
  108. /// <param name="urlEdit">{0}=ID 默认 ?op=edit&arg={0}</param>
  109. /// <param name="urlDelete">{0}=ID 默认 ?op=delete&arg={0}</param>
  110. public static void RenderGrid(Control container, IEnumerable<T> dataSource, string[] arrSkipFields
  111. , Func<Type, object[], object[]> fkQuery = null
  112. , string urlEdit = null
  113. , string urlDelete = null
  114. , int pageIndex = 0, int pageSize = 0)
  115. {
  116. //init vars
  117. urlEdit = urlEdit ?? "?op=edit&arg={0}";
  118. urlDelete = urlDelete ?? "?op=delete&arg={0}";
  119. //init
  120. var tbl = new Table();
  121. container.Controls.Add(tbl);
  122. tbl.Attributes.Add("border", "1");
  123. tbl.Style[HtmlTextWriterStyle.BorderCollapse] = "Collapse";
  124. tbl.CellSpacing = 1;
  125. tbl.CellPadding = 2;
  126. arrSkipFields = arrSkipFields ?? new string[] { };
  127. var arrFieldsToDisplay = AllField
  128. .Where(p => arrSkipFields.Contains(p.FieldName) == false)
  129. .ToArray();
  130. //header
  131. var th = new TableRow();
  132. th.Cells.Add(new TableHeaderCell { Text = "#" });
  133. th.Cells.AddRange(
  134. arrFieldsToDisplay
  135. .SelectArray(p => new TableHeaderCell { Text = p.DisplayName })
  136. );
  137. th.Cells.Add(new TableHeaderCell() { Text = "操作" });
  138. tbl.Rows.Add(th);
  139. //coll fk td for batch process
  140. List<FieldFK<T>> lstFKs = new List<FieldFK<T>>();
  141. int rowNumber = pageIndex * pageSize;
  142. //rows
  143. foreach (var item in dataSource)
  144. {
  145. var tr = new TableRow();
  146. tbl.Rows.Add(tr);
  147. tr.Cells.Add(new TableCell { Text = (++rowNumber).ToString() });
  148. //entity data
  149. tr.Cells.AddRange(
  150. arrFieldsToDisplay
  151. .SelectArray(p =>
  152. {
  153. var objVal = p.GetValue(item);
  154. var strVal = objVal.ToDisplayString();
  155. var td = new TableCell();
  156. td.VisualText(strVal);
  157. if (p.IsFK && objVal != null)
  158. {
  159. lstFKs.Add(new FieldFK<T> { Field = p, Td = td, FKVal = objVal });
  160. }
  161. return td;
  162. })
  163. );
  164. //opt.
  165. var tdOpt = new TableCell();
  166. tr.Cells.Add(tdOpt);
  167. object key = PkField.GetValue(item);
  168. tdOpt.Controls.Add(new HyperLink() { Text = "修改", NavigateUrl = urlEdit.Format(key) });
  169. tdOpt.Controls.Add(new Literal() { Text = " " });
  170. tdOpt.Controls.Add(new HyperLink() { Text = "删除", NavigateUrl = urlDelete.Format(key) });
  171. }//end foreach
  172. if (fkQuery != null)
  173. {
  174. ProcTdFK(fkQuery, lstFKs);
  175. }
  176. }
  177. public static void RenderInputForm(WebControl container, Action actOnSubmit, bool isAdd = true)
  178. {
  179. //init
  180. var tbl = new Table();
  181. container.Controls.Add(tbl);
  182. tbl.Attributes.Add("border", "1");
  183. tbl.Style[HtmlTextWriterStyle.BorderCollapse] = "Collapse";
  184. tbl.CellSpacing = 1;
  185. tbl.CellPadding = 2;
  186. //generate fields of form
  187. foreach (var field in AllField)
  188. {
  189. if (isAdd && field.IsPK)
  190. continue;
  191. var validation = field.Validation;
  192. var tr = new TableRow();
  193. tbl.Rows.Add(tr);
  194. //field name
  195. var tdName = tr.Cells.AddEx(new TableCell() { Text = field.DisplayName + ":" });
  196. if (field.AllowNull == false)
  197. {
  198. tdName.Controls.Add(new Literal() { Text = "[" });
  199. tdName.Controls.Add(new Label() { Text = "*", ForeColor = Color.Red });
  200. tdName.Controls.Add(new Literal() { Text = "]" });
  201. tdName.Controls.Add(new Literal() { Text = field.DisplayName + ":" });
  202. }
  203. //field control
  204. var tdCtl = new TableCell();
  205. tr.Cells.Add(tdCtl);
  206. Control ctl;
  207. ctl = field.CreateControl();
  208. if (field.IsPK)
  209. {
  210. if (ctl is TextBox)
  211. {
  212. var tc = (TextBox)ctl;
  213. tc.ReadOnly = true;
  214. //tc.BorderStyle = BorderStyle.None;
  215. }
  216. }
  217. if (field.HasDefaultValueGenerator)
  218. DymWebFormControlMappnig.GetInst(field.DataType, field.ValidationType).ControlSetValue(ctl, field.GenerateDefaultValue());
  219. tdCtl.Controls.Add(ctl);
  220. ctl.ID = field.ControlID;
  221. //hint
  222. if (!isAdd && validation is DynWebFormPasswordValidation)
  223. {
  224. tdCtl.Controls.Add(new Literal() { Text = "<br>*留空保持不变" });
  225. tdName.VerticalAlign = VerticalAlign.Top;
  226. }
  227. //field validate
  228. var tdVal = new TableCell();
  229. tr.Cells.Add(tdVal);
  230. if (field.IsPK == false
  231. && field.AllowNull == false
  232. && ctl is CheckBox == false
  233. && (
  234. (isAdd)
  235. || (!isAdd && false == validation is DynWebFormPasswordValidation)
  236. )
  237. )
  238. {
  239. var rfv = new RequiredFieldValidator();
  240. tdVal.Controls.Add(rfv);
  241. rfv.ValidationGroup = "fc" + Type.Name;
  242. rfv.ControlToValidate = ctl.ID;
  243. rfv.Display = ValidatorDisplay.Dynamic;
  244. rfv.ForeColor = Color.Red;
  245. rfv.Text = "*";
  246. rfv.ErrorMessage = "必填字段:<b>" + field.DisplayName + "</b>";
  247. rfv.ID = "rfv" + ctl.ID;
  248. }
  249. if (validation != null)
  250. {
  251. BaseValidator vc = validation.CreateValidator(container);
  252. tdVal.Controls.Add(vc);
  253. vc.ValidationGroup = "fc" + Type.Name;
  254. vc.ControlToValidate = ctl.ID;
  255. vc.Display = ValidatorDisplay.Dynamic;
  256. vc.ForeColor = Color.Red;
  257. vc.Text = "▲";
  258. vc.ErrorMessage = "无效输入:<b>" + field.DisplayName + "</b>";
  259. vc.ID = "cv" + ctl.ID;
  260. }
  261. }
  262. //the submit button
  263. var trSubmit = new TableRow();
  264. tbl.Rows.Add(trSubmit);
  265. var tdSubmit = new TableCell();
  266. trSubmit.Cells.Add(tdSubmit);
  267. tdSubmit.ColumnSpan = 3;
  268. tdSubmit.HorizontalAlign = HorizontalAlign.Right;
  269. tdSubmit.Controls.AddEx(new Button()
  270. {
  271. Text = "提交",
  272. ValidationGroup = "fc" + Type.Name
  273. }).Click += (ss, ee) =>
  274. {
  275. if (((Page)HttpContext.Current.Handler).IsValid)
  276. actOnSubmit();
  277. };
  278. //the summary
  279. var trSummarny = new TableRow();
  280. tbl.Rows.Add(trSummarny);
  281. var tdSummary = new TableCell();
  282. trSummarny.Cells.Add(tdSummary);
  283. tdSummary.ColumnSpan = 3;
  284. tdSummary.Controls.Add(new ValidationSummary() { ValidationGroup = "fc" + Type.Name, ForeColor = Color.Red });
  285. }
  286. public static void BindForm(WebControl container, T entity, bool isAdd = false)
  287. {
  288. AllField.ForEach(p =>
  289. {
  290. var val = p.GetValue(entity);
  291. var octl = container.FindControl(p.ControlID);
  292. DymWebFormControlMappnig.GetInst(p.DataType, p.ValidationType).ControlSetValue(octl, val);
  293. });
  294. }
  295. public static void BindEntity(WebControl container, T entity)
  296. {
  297. if (container == null)
  298. throw new ArgumentNullException("container");
  299. AllField
  300. .Where(p => p.IsPK == false)
  301. .ForEach(p =>
  302. {
  303. var octl = container.FindControl(p.ControlID);
  304. var val = DymWebFormControlMappnig.GetInst(p.DataType, p.ValidationType).ControlGetValue(octl);
  305. if (p.Validation is DynWebFormPasswordValidation
  306. && (val == null || val as string == "")
  307. )
  308. return;
  309. p.SetValue(entity, val);
  310. });
  311. }
  312. public static void RenderDetails(WebControl container, T entity, Func<Type, object[], object[]> fkQuery = null, string[] arrSkipFields = null)
  313. {
  314. RenderDetailsInternal(container, entity, fkQuery, arrSkipFields);
  315. }
  316. public static void RenderDelete(WebControl container, T entity, Action actOnDeleteSubmit, Func<Type, object[], object[]> fkQuery = null, string[] skipFields = null)
  317. {
  318. var tbl = RenderDetailsInternal(container, entity, fkQuery, skipFields);
  319. //the submit button
  320. var trSubmit = new TableRow();
  321. tbl.Rows.Add(trSubmit);
  322. var tdSubmit = new TableCell();
  323. trSubmit.Cells.Add(tdSubmit);
  324. tdSubmit.ColumnSpan = 3;
  325. tdSubmit.HorizontalAlign = HorizontalAlign.Right;
  326. tdSubmit.Controls.AddEx(new Button()
  327. {
  328. Text = "删除",
  329. }).Click += (ss, ee) =>
  330. {
  331. if (((Page)HttpContext.Current.Handler).IsValid)
  332. actOnDeleteSubmit();
  333. };
  334. }
  335. public static Dictionary<string, string> GetFieldNamesForGrid()
  336. {
  337. return AllField
  338. .Where(p => false == p.Validation is DynWebFormPasswordValidation)
  339. .ToDictionary(p => p.FieldName, p => p.DisplayName);
  340. }
  341. public static PropertyInfo GetFieldInfoForGrid(string name)
  342. {
  343. return AllField
  344. .Where(p => p.FieldName == name && false == p.Validation is DynWebFormPasswordValidation)
  345. .Select(p => p.PropertyInfo)
  346. .FirstOrDefault();
  347. }
  348. }
  349. }