从零开始编写自己的C#框架(21)——添加分类类型页面
页面权限与页面控件权限经过简单的调试后,终于启用起来了,以后大家添加新页面时,就必须按照本章介绍的方法,将你新增的页面注册到系统中,这样才能访问与进行相关操作。
下面讲讲如何创建一个分类类型的页面。
分类类型,顾名思义指的是按照一定规律、特点进行归类划分,放到一块的集合。我们开发时这些分类类型,经常用下拉列表来表现,如果有多级分类时,采用的是下拉树列表方式显示。
普通下拉列表
下拉树列表
下面将介绍如何从创建数据表、修改文件到权限绑定逐个步骤进行说明。
首先,我们先要创建好数据表
我们打开数据字典,按数据字典中的格式,创建一个广告位置管理表
然后打开大神July提供的SQL语句生成工具,生成数据表创建语句
运行ExcelToSQLString2.91_sql.exe,选择《数据字典》的文件路径,设置想要生成SQL语句的表格名称,然后点击运行
生成下面语句
将生成的语句放到SQL的查询分析器中执行,生成数据表(见下图已生成的数据表)
打开解决方案,找到数据层的SubSonic文件夹,按下图进行选择后,点击右键,找到“运行自定义工具”,点击重新运行生成数据层模板类
找到逻辑层的SubSonic文件夹,按下图进行选择后,点击右键,找到“运行自定义工具”,点击重新运行生成逻辑层模板类
通过以上操作,已经帮我们生成了底层我们需要调用到的常用实体和函数了,下面接着创建相关文件
为了方便管理,我们在UI层后端管理文件夹(WebManage)中创建一个AdvertisingPositions文件夹,用于存放广告管理的相关文件
已创建好文件夹
打开Informations文件夹,将InformationClassList.aspx复制到AdvertisingPositions文件夹中(因为这两个文件的功能比较相似,所以直接复制过来修改)
将InformationClassList.aspx改名为AdvertisingPositionList.aspx
打开AdvertisingPositionList.aspx与AdvertisingPositionList.aspx.cs文件,按下面方式进行替换
将页面中的“InformationClass”替换成“AdvertisingPosition”
将页面中的“信息分类”替换为“广告位置”
找到AdvertisingPositionList.aspx.cs文件的命名空间,将Informations替换成AdvertisingPositions,如下图
同样找到AdvertisingPositionList.aspx文件也进行同面的替换
经过替换,页面大体的功能就完成了。
打开AdvertisingPositionList.aspx文件,将Grid中想要显示的列重新进行设置绑定(按下面内容进行修改,具体怎么使用FineUI,大家可以登陆FineUI官网查看在线示例,或者先按我代码中的内容尝试对控件属性进行增改操作后刷新页面,查看修改后的效果,弄上几个就很容易明白怎么使用了)
1 <f:Grid ID="Grid1" Title="广告位置列表" EnableFrame="false" EnableCollapse="true" AllowSorting="true" 2 PageSize="15" ShowBorder="true" ShowHeader="False" AllowPaging="true" runat="server" EnableCheckBoxSelect="True" DataKeyNames="Id" EnableColumnLines="true" 3 OnPageIndexChange="Grid1_PageIndexChange" OnPreRowDataBound="Grid1_PreRowDataBound" OnRowCommand="Grid1_RowCommand"> 4 <Columns> 5 <f:BoundField DataField="Id" HeaderText="位置ID" Width="50px" /> 6 <f:TemplateField HeaderText="位置图" Width="60px"> 7 <ItemTemplate> 8 <%# Eval("MapImg").ToString().Length > 5 ? "<a href='" + Eval("MapImg").ToString() + "' target=\"_blank\" class='PicToolTip'><img src='" + DirFileHelper.GetFilePathPostfix(Eval("MapImg")+ "", "s") + "'></a>" : ""%> 9 </ItemTemplate> 10 </f:TemplateField> 11 <f:BoundField Width="150px" DataField="Name" DataFormatString="{0}" DataSimulateTreeLevelField="Depth" HeaderText="名称" /> 12 <f:BoundField DataField="Keyword" HeaderText="关键字" Width="100px" /> 13 <f:BoundField DataField="Width" HeaderText="宽" /> 14 <f:BoundField DataField="Height" HeaderText="高" /> 15 <f:TemplateField HeaderText="排序" Width="100px"> 16 <ItemTemplate> 17 <asp:TextBox ID="tbSort" runat="server" Width="50px" Text='<%# Eval("Sort") %>' AutoPostBack="false"></asp:TextBox> 18 </ItemTemplate> 19 </f:TemplateField> 20 <f:LinkButtonField HeaderText="是否显示" Icon="BulletCross" TextAlign="Center" ToolTip="点击修改是否显示" ColumnID="IsDisplay" CommandName="IsDisplay" /> 21 <f:BoundField DataField="Depth" HeaderText="级别层次" TextAlign="Center" /> 22 <f:LinkButtonField HeaderText="操作" TextAlign="Center" ToolTip="点击修改当前记录" ColumnID="ButtonEdit" CommandName="ButtonEdit" /> 23 </Columns> 24 </f:Grid>
打开AdvertisingPositionList.aspx.cs文件,我们会看到一些调用函数不存在或是提示出错,那么我们就动手创建或修改一下就可以了
由于绑定下拉列表函数我们的模板没有生成,所以就手动创建一下
同理,我们按InformationClassBll逻辑类的内容,创建AdvertisingPositionBll逻辑类
1 using System; 2 using System.Collections.Generic; 3 using System.Web.UI; 4 using DotNet.Utilities; 5 using Solution.DataAccess.DataModel; 6 7 /*********************************************************************** 8 * 作 者:AllEmpty(陈焕)-- 1654937@qq.com 9 * 博 客:http://www.cnblogs.com/EmptyFS/ 10 * 技 术 群:327360708 11 * 12 * 创建日期:2014-07-07 13 * 文件名称:AdvertisingPositionBll.cs 14 * 描 述:广告位置管理逻辑类 15 * 16 * 修 改 人: 17 * 修改日期: 18 * 修改原因: 19 ***********************************************************************/ 20 namespace Solution.Logic.Managers 21 { 22 /// <summary> 23 /// AdvertisingPositionBll逻辑类 24 /// </summary> 25 public partial class AdvertisingPositionBll : LogicBase 26 { 27 /*********************************************************************** 28 * 自定义函数 * 29 ***********************************************************************/ 30 31 #region 自定义函数 32 33 #region 绑定广告位置下拉列表 34 /// <summary> 35 /// 绑定广告位置下拉列表——只显示一级广告位置 36 /// </summary> 37 public void BandDropDownList(Page page, FineUI.DropDownList ddl) 38 { 39 var dt = DataTableHelper.GetFilterData(GetDataTable(), AdvertisingPositionTable.ParentId, "0", AdvertisingPositionTable.Sort, "desc"); 40 41 //显示值 42 ddl.DataTextField = AdvertisingPositionTable.Name; 43 //绑定Id 44 ddl.DataValueField = AdvertisingPositionTable.Id; 45 46 //绑定数据源 47 ddl.DataSource = dt; 48 ddl.DataBind(); 49 ddl.Items.Insert(0, new FineUI.ListItem("请选择广告位置", "0")); 50 ddl.SelectedValue = "0"; 51 } 52 53 /// <summary> 54 /// 绑定广告位置下拉列表——显示所有 55 /// </summary> 56 public void BandDropDownListShowAll(Page page, FineUI.DropDownList ddl) 57 { 58 //设置排序 59 var sortList = new List<string>(); 60 sortList.Add(AdvertisingPositionTable.Depth); 61 sortList.Add(AdvertisingPositionTable.Sort); 62 63 //筛选记录 64 var dt = GetDataTable(false, 0, null, 0, 0, null, sortList); 65 66 try 67 { 68 //整理出有层次感的数据 69 dt = DataTableHelper.DataTableTidyUp(dt, AdvertisingPositionTable.Id, AdvertisingPositionTable.ParentId, 0); 70 71 ddl.EnableSimulateTree = true; 72 73 //显示值 74 ddl.DataTextField = AdvertisingPositionTable.Name; 75 //绑定Id 76 ddl.DataValueField = AdvertisingPositionTable.Id; 77 //数据层次 78 ddl.DataSimulateTreeLevelField = AdvertisingPositionTable.Depth; 79 //绑定数据源 80 ddl.DataSource = dt; 81 ddl.DataBind(); 82 ddl.SelectedIndex = 0; 83 84 ddl.Items.Insert(0, new FineUI.ListItem("请选择广告位置", "0")); 85 ddl.SelectedValue = "0"; 86 } 87 catch (Exception e) 88 { 89 // 记录日志 90 CommonBll.WriteLog("", e); 91 } 92 } 93 #endregion 94 95 #endregion 自定义函数 96 } 97 }
接口函数与数据加载函数在前面的章节已经讲述过了,这里就不再重复说明
列表属性绑定,一般指的是页面中列表的列控件、点击事件、翻页事件、排序事件......等各种列表控件事件的绑定,对于翻页与排序事件,我们在父类中已经实现了,所以不用再进行处理,而这里我们要做的功能是,点击列表中的状态项进行更新,比如当前记录的状态是允许该记录显示出来,那么点击后就自动更改为隐藏状态。
对于这里,我们按下面代码修改一下
1 #region 列表属性绑定 2 3 #region 列表按键绑定——修改列表控件属性 4 /// <summary> 5 /// 列表按键绑定——修改列表控件属性 6 /// </summary> 7 /// <param name="sender"></param> 8 /// <param name="e"></param> 9 protected void Grid1_PreRowDataBound(object sender, FineUI.GridPreRowEventArgs e) 10 { 11 //绑定是否显示状态列 12 GridRow gr = Grid1.Rows[e.RowIndex]; 13 if (((System.Data.DataRowView)(gr.DataItem)).Row.Table.Rows[e.RowIndex][AdvertisingPositionTable.IsDisplay].ToString() == "0") 14 { 15 var lbf = Grid1.FindColumn("IsDisplay") as LinkButtonField; 16 lbf.Icon = Icon.BulletCross; 17 lbf.CommandArgument = "1"; 18 } 19 else 20 { 21 var lbf = Grid1.FindColumn("IsDisplay") as LinkButtonField; 22 lbf.Icon = Icon.BulletTick; 23 lbf.CommandArgument = "0"; 24 } 25 26 //绑定是否编辑列 27 var lbfEdit = Grid1.FindColumn("ButtonEdit") as LinkButtonField; 28 lbfEdit.Text = "编辑"; 29 lbfEdit.Enabled = MenuInfoBll.GetInstence().CheckControlPower(this, "ButtonEdit"); 30 } 31 #endregion 32 33 #region Grid点击事件 34 /// <summary> 35 /// Grid点击事件 36 /// </summary> 37 /// <param name="sender"></param> 38 /// <param name="e"></param> 39 protected void Grid1_RowCommand(object sender, FineUI.GridCommandEventArgs e) 40 { 41 GridRow gr = Grid1.Rows[e.RowIndex]; 42 //获取当前点击列的主键ID 43 object id = gr.DataKeys[0]; 44 45 switch (e.CommandName) 46 { 47 case "IsDisplay": 48 //更新状态 49 AdvertisingPositionBll.GetInstence().UpdateIsDisplay(this, ConvertHelper.Cint0(id), ConvertHelper.Cint0(e.CommandArgument)); 50 //重新加载 51 LoadData(); 52 53 break; 54 case "ButtonEdit": 55 //打开编辑窗口 56 Window1.IFrameUrl = "AdvertisingPositionEdit.aspx?Id=" + id + "&" + MenuInfoBll.GetInstence().PageUrlEncryptStringNoKey(id + ""); 57 Window1.Hidden = false; 58 59 break; 60 } 61 } 62 #endregion 63 64 #endregion
对于AdvertisingPositionBll.GetInstence().UpdateIsDisplay()函数的调用,如果没有细心留意前面章节的朋友,可能会比较奇怪怎么有这个函数,这是因为我们在设计数据库时,所有状态类的字段都会设置为tinyint类型,当逻辑层代码生成模板检测到字段类型为tinyint时,就会生成一个更新状态的函数提供给我们调用,这样我们就无需去编写这些常用的函数了,直接拿来使用即可。
比较一下这里列表属性绑定后的效果
对于记录删除函数,一般在删除前我们都必须判断一下,看看该记录是否已给其他表引用了,是的话则不能直接删除(因为直接删掉的话有可能会引起其他表使用时的异常或数据同步查询等问题),另外如果存在图片的也必须先删掉图片,当然图片删除函数我们的逻辑层模板也生成好了,直接引用就可以了。这些都处理好才直接执行记录删除函数删除记录。
由于我们的广告表未创建,所以这里我们先将广告位置是否给广告表引表的检查注释掉。
1 #region 删除记录 2 /// <summary> 3 /// 删除记录 4 /// </summary> 5 /// <returns></returns> 6 public override string Delete() 7 { 8 //获取要删除的ID 9 int id = ConvertHelper.Cint0(GridViewHelper.GetSelectedKey(Grid1, true)); 10 11 //如果没有选择记录,则直接退出 12 if (id == 0) 13 { 14 return "请选择要删除的记录。"; 15 } 16 17 try 18 { 19 //删除前判断一下 20 if (AdvertisingPositionBll.GetInstence().Exist(x => x.ParentId == id)) 21 { 22 return "删除失败,本广告位置下面存在子广告位置,不能直接删除!"; 23 } 24 //删除前判断一下 25 //if (InformationBll.GetInstence().Exist(x => x.AdvertisingPosition_Id == id)) 26 //{ 27 // return "删除失败,本广告位置已被信息表的记录引用,不能直接删除!"; 28 //} 29 30 //删除记录 31 bll.Delete(this, id); 32 33 return "删除编号ID为[" + id + "]的数据记录成功。"; 34 } 35 catch (Exception e) 36 { 37 string result = "尝试删除编号ID为[" + id + "]的数据记录失败!"; 38 39 //出现异常,保存出错日志信息 40 CommonBll.WriteLog(result, e); 41 42 return result; 43 } 44 } 45 #endregion
这里还有个地方要同大家讲一讲,对于页面列表,我们选中了一列、或多列时,怎么取得选中列的主键Id呢?这里我们可以调用下面三个函数来获取:GridViewHelper.GetSelectedKey()——用于获取选中单条的记录Id、GridViewHelper.GetSelectedKeyArray()——用于获取多记录时的Id数组、GridViewHelper.GetSelectedKeyAll()——用于获取单选项中,设置了多个绑定字段时,返回这多个字段值的数组。
对于最后这个,我们有时候需要选中项传回多个字段值时,可以在表格Grid设置属性DataKeyNames="Id, Name, Keyword",那么使用GridViewHelper.GetSelectedKeyAll()就可以获取当前选中记录的这三个字段值。
做到这一步,代码的修改已经算是完成了,我们执行一下编译,看看有没有通过,如果没有再检查一下原因。
这样做完后,我们登陆后端管理系统,并没有发现菜单中存在广告链接,所以接下来我们要将已完成的广告注册到后端管理系统中。
我们登陆后端管理系统,进入系统管理=》权限管理=》菜单管理,点击新增按钮
为了方便菜单的管理,我们先创建广告管理菜单,如下图,填写菜单名称为广告管理;节点不用选择;填入广告所在的文件夹路径;排序号我们可以选填写2,将广告管理放到信息管理项(该项排序值为1)的后面,如果填写0的话,将自动生成同级别最大的排序值,放到最后面;是否菜单或页面那里,选择菜单(在后面绑定页面控件时,菜单是不能绑定页面控件的,只有页面才能绑定);是否显示这里当然是选择在菜单栏中显示出来。填好后点击保存生成广告管理菜单。
然后我们添加广告位置管理菜单
填写完以后,我们刷新页面发现广告管理并没有在菜单栏显示出来,这是因为我们还没有为当前帐号绑定权限
在我们绑定权限前,先要为页面绑定控件
我们打开系统管理=》权限管理=》页面权限设置,点击左栏的广告位置管理,将添加、编辑、删除、自动排序、保存排序这几个控件选择后点击中间的>>按钮,将它们绑定好该页面
然后点击职位管理,找到当前管理所在的部门与职位——技术部--软件开发工程师
点击编辑可以看到下图内容,我们点击广告管理就可以将所有管理项权限都赋给该职位了
然后点击顶部的,退出系统重新登陆后,就可以在菜单栏上查看到广告位置管理链接了
如果对添加、编辑、删除等按钮权限没有打勾或没有在页面控件中绑定的话,就会出现下图情况,程序默认该用户对这些按钮没有操作权限,打开页面后页面将会自动将这些按钮禁用
接着我们添加广告编辑页面
同样复制InformationClassEdit.aspx文件并改名为AdvertisingPositionEdit.aspx
同样做上面的替换操作
然后打开AdvertisingPositionEdit.aspx文件,编辑显示的控件
1 <f:TextBox runat="server" ID="txtName" Label="位置名称" ShowRedStar="true" Width="250px"> 2 </f:TextBox> 3 <f:TextBox runat="server" ID="txtKey" Label="关键字" ShowRedStar="true" Width="250px"> 4 </f:TextBox> 5 <f:DropDownList Label="所属位置选择" AutoPostBack="true" Required="true" CompareType="String" 6 EnableSimulateTree="true" runat="server" ID="ddlParentId" Width="200px" OnSelectedIndexChanged="ddlParentId_SelectedIndexChanged"> 7 </f:DropDownList> 8 <f:TextBox Readonly="true" runat="server" ID="txtParent" Label="父Id" EmptyText="对应的父类Id" 9 Width="100px" Text="0"> 10 </f:TextBox> 11 <f:TextBox runat="server" ID="txtSort" Label="排序" Width="250px" Text="0"></f:TextBox> 12 <f:RadioButtonList ID="rblIsDisplay" Label="是否显示" ColumnNumber="2" runat="server" 13 ShowRedStar="true" Required="true"> 14 <f:RadioItem Text="显示" Value="1" Selected="true"/> 15 <f:RadioItem Text="不显示" Value="0" /> 16 </f:RadioButtonList> 17 <f:FileUpload runat="server" ID="MapImg" Label="位置图" Width="250px" /> 18 <f:Button runat="server" Text="删除位置图" OnClick="BtnDelMapImg_Click"></f:Button> 19 <f:Image runat="server" ID="imgMap"></f:Image> 20 <f:FileUpload runat="server" ID="PicImg" Label="默认广告图" Width="250px" /> 21 <f:Button runat="server" Text="删除默认图" OnClick="BtnDelPicImg_Click"></f:Button> 22 <f:Image runat="server" ID="imgPic"></f:Image> 23 <f:HiddenField runat="server" ID="hidId" Text="0"></f:HiddenField>
对于编辑页面对应的cs文件,如果页面比较简单的话,我们一般要做的处理就是对对aspx页面的控件进行赋值操作,还有就是存储处理。
对于AdvertisingPositionEdit.aspx.cs文件,同样我们也是先在加载数据函数中,对页面控件进行赋值操作。
通过逻辑层的GetModelForCache()函数来读取记录实体(这里要注意的是,如果数据表的记录可能会比较多的时候,我们就不要使用数据缓存功能,这样会加大服务器的负担,我们直接使用GetModel(id, false)函数直接从数据库中读取实体),然后对页面控件逐个赋值。对于下拉列表的绑定,编辑时不建议开启修改,因为修改时编辑人员可能会更改当前节点到其他级别的父类,这样操作需要在保存函数里做相当多的判断处理,增大开发的工作量。
1 #region 加载数据 2 /// <summary>读取数据</summary> 3 public override void LoadData() 4 { 5 int id = ConvertHelper.Cint0(hidId.Text); 6 7 if (id != 0) 8 { 9 //获取指定ID的广告位置内容 10 var model = AdvertisingPositionBll.GetInstence().GetModelForCache(x => x.Id == id); 11 if (model == null) 12 return; 13 14 //地址名称 15 txtName.Text = model.Name; 16 //给下拉列表赋值 17 ddlParentId.SelectedValue = model.ParentId + ""; 18 //编辑时不能修改父节点 19 ddlParentId.Enabled = false; 20 //设置父ID 21 txtParent.Text = model.ParentId + ""; 22 //设置排序 23 txtSort.Text = model.Sort + ""; 24 //KEY 25 txtKey.Text = model.Keyword; 26 //给页面图片赋值 27 if (model.MapImg != null && model.MapImg.Length > 5) 28 { 29 imgMap.ImageUrl = DirFileHelper.GetFilePathPostfix(model.MapImg, "s"); 30 } 31 else 32 { 33 //不存在图片,则隐藏图片控件和图片删除按钮 34 imgMap.Visible = false; 35 ButtonDelMapImg.Visible = false; 36 } 37 //给页面图片赋值 38 if (model.PicImg != null && model.PicImg.Length > 5) 39 { 40 imgPic.ImageUrl = DirFileHelper.GetFilePathPostfix(model.PicImg, "s"); 41 } 42 else 43 { 44 //不存在图片,则隐藏图片控件和图片删除按钮 45 imgPic.Visible = false; 46 ButtonDelPicImg.Visible = false; 47 } 48 //是否显示(状态) 49 rblIsDisplay.SelectedValue = model.IsDisplay + ""; 50 51 } 52 else 53 { 54 //新建广告位置时,隐藏图片控件和图片删除按钮 55 imgMap.Visible = false; 56 imgPic.Visible = false; 57 ButtonDelMapImg.Visible = false; 58 ButtonDelPicImg.Visible = false; 59 } 60 } 61 62 #endregion
添加删除图片按钮函数,从下列代码中可以看到,删除函数都是调用模板生成的
1 #region 删除图片 2 /// <summary> 3 /// 删除位置图 4 /// </summary> 5 /// <param name="sender"></param> 6 /// <param name="e"></param> 7 protected void ButtonDelMapImg_Click(object sender, EventArgs e) 8 { 9 AdvertisingPositionBll.GetInstence().DelMapImg(this, ConvertHelper.Cint0(hidId.Text)); 10 //删除后刷新编辑窗口 11 Response.Redirect(Request.Url.ToString()); 12 } 13 14 /// <summary> 15 /// 删除默认图片 16 /// </summary> 17 /// <param name="sender"></param> 18 /// <param name="e"></param> 19 protected void ButtonDelPicImg_Click(object sender, EventArgs e) 20 { 21 AdvertisingPositionBll.GetInstence().DelPicImg(this, ConvertHelper.Cint0(hidId.Text)); 22 //删除后刷新编辑窗口 23 Response.Redirect(Request.Url.ToString()); 24 } 25 #endregion
进入保存操作时,一般我们要先对输入的数据进行检查,检查必填项是否为空,检查指定项在数据库中是否存在重复项等内容,然后获取或创建编辑实体,跟着检查相关项是否有修改,有的话保存成功后需要同步修改其他关联表对应的字段,接着是读取页面控件值对实体进行赋值操作,如果有图片上传的,则调用上传方法上传图片,再然后就是保存实体,同步更新关联表字段。
首先检查检查必填项是否为空,检查指定项在数据库中是否存在重复项等内容
1 #region 数据验证 2 3 if (string.IsNullOrEmpty(txtName.Text.Trim())) 4 { 5 return txtName.Label + "不能为空!"; 6 } 7 var sName = StringHelper.FilterSql(txtName.Text, true); 8 if (AdvertisingPositionBll.GetInstence().Exist(x => x.Name == sName && x.Id != id)) 9 { 10 return txtName.Label + "已存在!请重新输入!"; 11 } 12 if (string.IsNullOrEmpty(txtKey.Text.Trim())) 13 { 14 return txtKey.Label + "不能为空!"; 15 } 16 var sKeyword = StringHelper.FilterSql(txtKey.Text, true); 17 if (AdvertisingPositionBll.GetInstence().Exist(x => x.Keyword == sKeyword && x.Id != id)) 18 { 19 return txtKey.Label + "已存在!请重新输入!"; 20 } 21 22 #endregion
在开发时要注意的是,使用lambda表达式传递条件时,必须先计算出值后,将存储值的变量放到lambda表达式中比较,而不能将计算的表达式作为值放在lambda表达式中比较,这样会出错的。
对相关项进行检查完毕后,跟着就是进行赋值操作,获取页面控件值进行SQL注入过滤或XSS过滤后,将值赋给实体。
对于页面控件值的获取,字符串类型一般都会使用StringHelper.Left(页面控件, 截取长度)函数来获取,让输入到数据库的字段值自动去掉两旁空格,并进行XSS过滤后,截取数据表字段规定的大小后存储过来,避免相关人员录入过长数据,而对于需要录入特殊符号的字段,可以使用StringHelper.Left(页面控件, 截取长度, true, false)函数来获取,这样就只进行SQL注入过滤,而不进行XSS过滤,具体请大家查看该函数,里面有详细注释。而对于数值型的则使用相关函数进行转换。
1 #region 赋值 2 //定义是否更新其他关联表变量 3 bool isUpdate = false; 4 5 //读取当前地址信息 6 var model = new AdvertisingPosition(x => x.Id == id); 7 8 //判断是否更新关联表 9 if (model.Id > 0 && sName != model.Name) 10 isUpdate = true; 11 12 //设置名称 13 model.Name = StringHelper.Left(txtName.Text, 50); 14 //KEY 15 model.Keyword = StringHelper.Left(txtKey.Text, 50); 16 //对应的父类id 17 model.ParentId = ConvertHelper.Cint0(txtParent.Text); 18 //由于限制了编辑时不能修改父节点,所以这里只对新建记录时处理 19 if (id == 0) 20 { 21 //设定当前的深度与设定当前的层数级 22 if (model.ParentId == 0) 23 { 24 //设定当前的层数级 25 model.Depth = 0; 26 } 27 else 28 { 29 //设定当前的层数 30 model.Depth = ConvertHelper.Cint0(AdvertisingPositionBll.GetInstence().GetFieldValue(ConvertHelper.Cint0(ddlParentId.SelectedValue), AdvertisingPositionTable.Depth)) + 1; 31 } 32 33 //限制分类层数只能为2层 34 if (model.Depth > 2) 35 { 36 return "广告位置只能创建2层分类!"; 37 } 38 } 39 //设置排序 40 if (txtSort.Text == "0") 41 { 42 model.Sort = AdvertisingPositionBll.GetInstence().GetSortMax(model.ParentId) + 1; 43 } 44 else 45 { 46 model.Sort = ConvertHelper.Cint0(txtSort.Text); 47 } 48 //设定当前项是否显示 49 model.IsDisplay = ConvertHelper.StringToByte(rblIsDisplay.SelectedValue); 50 51 //广告宽与高 52 model.Width = ConvertHelper.Cint0(txtWidth.Text); 53 model.Height = ConvertHelper.Cint0(txtHeight.Text); 54 55 //添加最后修改人员 56 model.Manager_Id = OnlineUsersBll.GetInstence().GetManagerId(); 57 model.Manager_CName = OnlineUsersBll.GetInstence().GetManagerCName(); 58 model.AddDate = DateTime.Now; 59 60 #endregion
如果页面需要上传图片的,则必须先在系统管理=》基础设置=》上传配置管理中,添加一项新的配置,取得新建的配置Id后,再使用图片上传方法来上传图片。具体上传类的使用我会在后面的章节单独讲解。
代码中绑定好对应的Id
最后是将实体保存到数据库,以及同步更新关联表字段,由于广告表未创建,所以暂时注释掉代码。
接下来要做的还是菜单注册与权限绑定操作,这里就不再继续重复了。
最终编辑页面实现效果:
上面内容看起来好像非常多很复杂的样子,实际上只要你做过几个例子,然后熟悉本框架的开发模式后就会感觉简单多了,整个操作来看,编码部分相对来说比较少,且绝大部分都是调用已生成好的模板函数,也就是说只要你熟悉了模板函数,想实现什么样的功能都不是很难,同时也不用自己编写大量的逻辑层以及数据层代码,一键生成。想轻松的使用本框架开发新功能,必须学会FineUI插件的相关调用,FineUI官方有在线示例,都比较简单。其实只要你将FineUI的控件属性,在页面中直接修改后刷新页面,查看其变化,逐个测试过后你就基本上掌握了,非常简单,我也是这样学习的。
整个操作所花费的时间更多是用在数据库表单的设计、UI的绘制,以及页面开发完成后在后端权限模块进行注册绑定。
使用本框架开发,更多的是让开发人员从复制粘贴工作中解放出来,不用编写大量的底层重复函数,更多的关注UI的制作以及业务逻辑设计。因为底层模块会将日志、安全检查、常用函数.....等功能已经帮我们实现了。
由于框架不是非常成熟,很多朋友不是用来学习而是直接用到项目中,但不熟悉框架引起不少小问题,所以停止提供下载,有需要学习的可以到群共享里下,不便之处敬请谅解。
版权声明:
本文由AllEmpty原创并发布于博客园,欢迎转载,未经本人同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。如有问题,可以通过1654937@qq.com 联系我,非常感谢。
发表本编内容,只要主为了和大家共同学习共同进步,有兴趣的朋友可以加加Q群:327360708 ,大家一起探讨。
更多内容,敬请观注博客:http://www.cnblogs.com/EmptyFS/