本文共 19073 字,大约阅读时间需要 63 分钟。
做网站,少不了页面,用.net做的话,aspx文件基本都是页面布局什么的,cs文件则是处理程序,这些都很普通啦
但每次在页面里调用变量的时候,都需要在cs里写一大堆东西用来支持页面调用,就很繁琐,很麻烦,很恶心了
然后,老顾就又想着怎么偷懒了。。。。。。怎么能减少cs的改动呢?
首先,我们把需要输出的内容定义成一个Hashtable,然后将Hashtable输出到页面
那么,我们先来实现这个吧
public static class PageControlHelper { private static Page CurrentPage { get { return HttpContext.Current.CurrentHandler as Page; } } public static void SetToControls(Hashtable ht) { Page page = CurrentPage; SetToControls(page, ht); } public static void SetToControls(Control ctl, Hashtable ht) { if (ht.Count != 0) { int size = ht.Keys.Count; foreach (string key in ht.Keys) { object val = ht[key]; if (val == null) { continue; } Control control = ctl.FindControl(key); if (control != null) { Type t = val.GetType(); if (t.Name == "bool" || t.Name == "Boolean") { val = (bool)val ? 1 : 0; } #region 根据control类型进行不同的赋值设置 #region CheckBoxList if (control is CheckBoxList) { CheckBoxList cbl = (CheckBoxList)control; string[] v = val.ToString().Split(new string[] { "," }, StringSplitOptions.None); foreach (ListItem li in cbl.Items) { for (int i = 0; i < v.Length; i++) { if (v[i] == li.Value || v[i].Trim() == li.Value) { li.Selected = true; } } } } #endregion #region RadioButtonList if (control is RadioButtonList) { RadioButtonList rbl = (RadioButtonList)control; rbl.SelectedValue = val.ToString(); } #endregion #region DropDownList if (control is DropDownList) { DropDownList ddl = (DropDownList)control; ddl.SelectedValue = val.ToString(); } #endregion #region TextBox if (control is TextBox) { TextBox tb = (TextBox)control; tb.Text = val.ToString(); } #endregion #region Label if (control is Label) { Label lab = (Label)control; lab.Text = val.ToString(); } #endregion #region HtmlSelect if (control is HtmlSelect) { HtmlSelect hs = (HtmlSelect)control; //hs.Items.FindByValue(val.ToString()).Selected = true; hs.Value = val.ToString(); } #endregion #region HtmlInputText,input type=text if (control is HtmlInputText) { HtmlInputText hit = (HtmlInputText)control; hit.Value = val.ToString(); } #endregion #region HtmlInputHidden,input type=hidden if (control is HtmlInputHidden) { HtmlInputHidden hih = (HtmlInputHidden)control; hih.Value = val.ToString(); } #endregion #region HtmlInputPassword,input type=password if (control is HtmlInputPassword) { HtmlInputPassword hip = (HtmlInputPassword)control; hip.Value = val.ToString(); } #endregion #region HtmlInputCheckBox,input type=checkbox,仅单一选项可用 if (control is HtmlInputCheckBox) { HtmlInputCheckBox htmlinputcheckbox = (HtmlInputCheckBox)control; if (val.ToString() == "1") { htmlinputcheckbox.Checked = true; } } #endregion #region HtmlTextArea,textarea标签 if (control is HtmlTextArea) { HtmlTextArea area = (HtmlTextArea)control; area.Value = val.ToString(); } #endregion #region HtmlImage,img标签 if (control is HtmlImage) { HtmlImage img = (HtmlImage)control; img.Src = val.ToString(); } #endregion #region HtmlAnchor,a标签 if (control is HtmlAnchor) { HtmlAnchor ha = (HtmlAnchor)control; ha.InnerHtml = val.ToString(); } #endregion #region HtmlGenericControl if (control is HtmlGenericControl) { HtmlGenericControl hgc = (HtmlGenericControl)control; hgc.InnerHtml = val.ToString(); } #endregion #endregion } } } } }
这个是用来实现,所有带有runat="server"的控件,自动获得Hashtable对应的值的
然后我们定义一个基类,让所有页面继承他
public Hashtable HT = new Hashtable(); protected override void OnLoad(EventArgs e) { base.OnLoad(e); // 在继承的页面里定义Hashtable的值 PageControlHelper.SetToControls(HT); }
这样就能直接输出到页面了,但这样还是不太方便,因为我们可能需要将值进行格式化,按照特定格式输出
怎么能支持一下呢?
于是老顾写了一个格式化的类
public static class TemplateParser { public static string Parse(string html, Hashtable ht = null) { string result = html; #region 替换$field$设置的变量 if (ht != null && ht.Count > 0) { // hashtable 转成datarow DataRow dr = DataBaseHelper.ToDataRow(ht); foreach (string key in ht.Keys) { result = RegexExpand.Replace(result, @"\$" + key + @"\$", ht[key] == null ? string.Empty : ht[key].ToString(), RegexOptions.IgnoreCase); MatchCollection ks = RegexExpand.Matches(result, @"\$" + key + @"\.[^$]+\$", RegexOptions.IgnoreCase); foreach (Match m in ks) { // 将 $field$格式变形成^field^格式进行解析 result = result.Replace(m.Value, Parse(dr, RegexExpand.Replace(m.Value, @"^\$|\$$", "^", RegexOptions.IgnoreCase))); } } } result = RegexExpand.Replace(result, @"[\$][a-z][a-z0-9_]*(\.[^\$\.]+)*[\$]", ""); #endregion return result; } public static class RefFun { public static string RefFun_Tostring(object val, string args = null) { string result = string.Empty; if (!string.IsNullOrEmpty(val.ToString())) { if (string.IsNullOrEmpty(args)) { result = val.ToString(); } else { Type t = val.GetType(); MethodInfo mi = t.GetMethod("ToString", new Type[] { typeof(string) }); if (mi != null) { result = (string)mi.Invoke(val, new object[] { args }); } else { result = val.ToString(); } } } return result; } } public static string Parse(DataRow row, string format) { string result = format; MatchCollection mc = RegexExpand.Matches(result, @"[\^](\w+)(?:\.([^\.]+?)((?:(\.[^\^\.]+)*?)?))?[\^]"); for (int i = 0; i < mc.Count; i++) { string field = mc[i].Groups[1].Value.ToUpper(); string arg = mc[i].Groups[2].Value.ToLower(); string para = mc[i].Groups[3].Value; // 如果DataRow存在对应字段 if (row.Table.Columns.IndexOf(field) > -1) { try { // 使用枚举定义链接类型 LinkType lt = LinkType.Default; OutputLinkType olt; object obj = row.ItemArray[row.Table.Columns.IndexOf(field)]; string val = obj.ToString(); #region 无参数仅字段名的直接输出 if (string.IsNullOrEmpty(arg)) { if (!string.IsNullOrEmpty(val.Trim())) { switch (obj.GetType().Name) { case "DateTime": val = ((DateTime)obj).ToString("yyyy-MM-dd"); break; case "Money": val = RegexExpand.Replace(val, @"\.\d+$", ""); break; case "Decimal": val = RegexExpand.Replace(val, @"\.\d+$", ""); break; } result = RegexExpand.Replace(result, RegexExpand.Replace(mc[i].Value, @"\^", "\\^"), val); } else { if (RegexExpand.IsMatch(result, @"(?<=<[^<>]*?)" + RegexExpand.Replace(mc[i].Value, @"\^", "\\^") + "(?=[^<>]*?>)", RegexOptions.IgnoreCase)) { result = RegexExpand.Replace(result, @"<(\w+)(?!\w)[^<>]*?" + RegexExpand.Replace(mc[i].Value, @"\^", "\\^") + @"([^<>]*?/>|([\s\S](?!<\1(?!\w)))*? ]*?>)", "", RegexOptions.IgnoreCase); } else { result = RegexExpand.Replace(result, @"(?<=(^|>))[^>]*?" + RegexExpand.Replace(mc[i].Value, @"\^", "\\^") + @"[^<]*?(?=(<|$))", ""); } } } #endregion #region 限长字符串 else if (RegexExpand.IsMatch(arg, @"^\d+$")) { int len = 0; int.TryParse(arg, out len); if (len > 0) { val = StringExpand.ByteSubstring(RegexExpand.Replace(val, @"<[^<>]*?>|[\r\n\s\t]| ", ""), len); } result = RegexExpand.Replace(result, RegexExpand.Replace(mc[i].Value, @"\^", "\\^"), val); } #endregion #region 尝试判断是否是链接格式 else if (Enum.TryParse(arg, out olt)) { lt = (LinkType)olt; result = RegexExpand.Replace(result, RegexExpand.Replace(mc[i].Value, @"\^", "\\^"), MakeLink(row.ItemArray[row.Table.Columns.IndexOf(field)].ToString(), lt, true)); // MakeLink用来生成链接,自行设置 } #endregion #region 尝试反射到方法 else { #region 尝试反射成功则以反射处理 Type t = typeof(RefFun); MethodInfo method = t.GetMethod("RefFun_" + RegexExpand.Replace(arg, @"^[a-z]+", RegexExpand.ToTitleCase, RegexOptions.IgnoreCase)); if (method != null) { try { ParameterInfo[] paras = method.GetParameters(); // 由于反射时,反射方法形参具有不同类型,所以根据形参类型预判断需要传递的实参值 if (paras[0].ParameterType == typeof(object)) { result = RegexExpand.Replace(result, RegexExpand.Replace(mc[i].Value, @"\^", "\\^"), (string)method.Invoke(null, new object[] { obj, RegexExpand.Replace(para, @"^\.", "") })); } else { result = RegexExpand.Replace(result, RegexExpand.Replace(mc[i].Value, @"\^", "\\^"), (string)method.Invoke(null, new object[] { val, RegexExpand.Replace(para, @"^\.", "") })); } } catch (Exception ex) { LogHelper.LogMessage(logType, ex, "RefFun_" + RegexExpand.Replace(arg, @"^[a-z]+", RegexExpand.ToTitleCase, RegexOptions.IgnoreCase) + " 值:" + val + ",异常:" + RegexExpand.Replace(para, @"^\.", "")); } } #endregion #region 当反射失败且未输出时使用最终处理 else { LogHelper.LogMessage(logType, mc[i].Value + " 无解析方法"); result = RegexExpand.Replace(result, RegexExpand.Replace(mc[i].Value, @"\^", "\\^"), row.ItemArray[row.Table.Columns.IndexOf(field)].ToString()); } #endregion } #endregion } catch (Exception ex) { LogHelper.LogMessage(logType, ex, "字段:" + field + ",参数:" + arg + para); } } } return result; } }
这样,我们可以对html存在的$field$类型的内容进行变量解析了,如果要输出特定格式,就自己再RefFun类里追加自己的解析方法即可,只要是RefFun_开头,后边跟方法名,然后方法名首字母大写,都可以通过反射调用了
那么,现在我们来实现,怎么通过基类进行调用这个解析吧
在PageControlHelper里,追加一个方法
public static void BindHashtableParameters(Hashtable ht, Control ctls = null) { ControlCollection cc = ctls == null ? CurrentPage.Controls : ctls.Controls; foreach (Control ctl in cc) { if (ctl.Controls.Count > 0) { BindHashtableParameters(ht, ctl); } if (ctl is RadioButtonList) { RadioButtonList rbl = (RadioButtonList)ctl; for (int i = 0; i < rbl.Items.Count; i++) { ListItem li = rbl.Items[i]; li.Text = TemplateParser.Parse(li.Text, ht); } } Type t = ctl.GetType(); string text = string.Empty; PropertyInfo pi = t.GetProperty("InnerHtml"); if (pi == null) { pi = t.GetProperty("Text"); } if (pi != null) { try { text = pi.GetValue(ctl, null).ToString(); } catch { continue; } } else { continue; } string parsed = TemplateParser.Parse(text, ht); if (text != parsed) { try { if (pi.CanWrite) { pi.SetValue(ctl, parsed, null); } else { if (ctl is DataBoundLiteralControl) { if (ctl.Parent is RepeaterItem) { RepeaterItem ri = ctl.Parent as RepeaterItem; ri.Controls.Clear(); LiteralControl lc = new LiteralControl(parsed); ri.Controls.Add(lc); } else { HtmlGenericControl parent = ctl.Parent as HtmlGenericControl; parent.InnerHtml = parsed; } } } } catch (Exception ex) { throw ex; } } } }
然后,修改我们的基类
public Hashtable HT = new Hashtable(); protected override void OnLoad(EventArgs e) { base.OnLoad(e); // 在继承的页面里定义Hashtable的值 PageControlHelper.BindHashtableParameters(HT); PageControlHelper.SetToControls(HT); }
这样,我们就可以对所有继承了这个基类的页面直接输出变量了,支持runat="server"控件,Hmmmm,但这个不支持格式化输出,支持$field$格式变量,这个支持格式化输出,例如$content.40$就是输出40个字符的内容,$datetime.tostring.yyyy-MM-dd HH:mm$就是格式化输出日期和时间
好了,这就可以偷懒了,除了部分特定运算,基本不再修改cs文件就可以将内容输出出来了,把所有从数据库获得的数据直接扔到hashtable里,让他自动解析吧!
有人说了,比如我的数据库里,有一个地域信息,但他是数值型的,我输出可不能是数字,那么,就自己定义RefFun吧,$city.city.full$,变量定义成类似这样的格式即可,第一个city是字段名,第二个city是RefFun_City这个方法的方法名,full就是输出格式什么的了
多定义几个常用的输出方式,那么后期就基本不再需要考虑变量输出问题了,越来越偷懒了
转载地址:http://ixvxi.baihongyu.com/