页面权限与页面控件权限经过简单的调试后,终于启用起来了,以后大家添加新页面时,就必须按照本章介绍的方法,将你新增的页面注册到系统中,这样才能访问与进行相关操作。

  下面讲讲如何创建一个分类类型的页面。

  分类类型,顾名思义指的是按照一定规律、特点进行归类划分,放到一块的集合。我们开发时这些分类类型,经常用下拉列表来表现,如果有多级分类时,采用的是下拉树列表方式显示。

  普通下拉列表

  

  下拉树列表

  

  下面将介绍如何从创建数据表、修改文件到权限绑定逐个步骤进行说明。

  

  首先,我们先要创建好数据表

  我们打开数据字典,按数据字典中的格式,创建一个广告位置管理表

  然后打开大神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官网查看在线示例,或者先按我代码中的内容尝试对控件属性进行增改操作后刷新页面,查看修改后的效果,弄上几个就很容易明白怎么使用了)

             <f:Grid ID="Grid1" Title="广告位置列表" EnableFrame="false" EnableCollapse="true" AllowSorting="true"
PageSize="" ShowBorder="true" ShowHeader="False" AllowPaging="true" runat="server" EnableCheckBoxSelect="True" DataKeyNames="Id" EnableColumnLines="true"
OnPageIndexChange="Grid1_PageIndexChange" OnPreRowDataBound="Grid1_PreRowDataBound" OnRowCommand="Grid1_RowCommand">
<Columns>
<f:BoundField DataField="Id" HeaderText="位置ID" Width="50px" />
<f:TemplateField HeaderText="位置图" Width="60px">
<ItemTemplate>
<%# Eval("MapImg").ToString().Length > ? "<a href='" + Eval("MapImg").ToString() + "' target=\"_blank\" class='PicToolTip'><img src='" + DirFileHelper.GetFilePathPostfix(Eval("MapImg")+ "", "s") + "'></a>" : ""%>
</ItemTemplate>
</f:TemplateField>
<f:BoundField Width="150px" DataField="Name" DataFormatString="{0}" DataSimulateTreeLevelField="Depth" HeaderText="名称" />
<f:BoundField DataField="Keyword" HeaderText="关键字" Width="100px" />
<f:BoundField DataField="Width" HeaderText="宽" />
<f:BoundField DataField="Height" HeaderText="高" />
<f:TemplateField HeaderText="排序" Width="100px">
<ItemTemplate>
<asp:TextBox ID="tbSort" runat="server" Width="50px" Text='<%# Eval("Sort") %>' AutoPostBack="false"></asp:TextBox>
</ItemTemplate>
</f:TemplateField>
<f:LinkButtonField HeaderText="是否显示" Icon="BulletCross" TextAlign="Center" ToolTip="点击修改是否显示" ColumnID="IsDisplay" CommandName="IsDisplay" />
<f:BoundField DataField="Depth" HeaderText="级别层次" TextAlign="Center" />
<f:LinkButtonField HeaderText="操作" TextAlign="Center" ToolTip="点击修改当前记录" ColumnID="ButtonEdit" CommandName="ButtonEdit" />
</Columns>
</f:Grid>

  打开AdvertisingPositionList.aspx.cs文件,我们会看到一些调用函数不存在或是提示出错,那么我们就动手创建或修改一下就可以了

  由于绑定下拉列表函数我们的模板没有生成,所以就手动创建一下

  同理,我们按InformationClassBll逻辑类的内容,创建AdvertisingPositionBll逻辑类

 using System;
using System.Collections.Generic;
using System.Web.UI;
using DotNet.Utilities;
using Solution.DataAccess.DataModel; /***********************************************************************
* 作 者:AllEmpty(陈焕)-- 1654937@qq.com
* 博 客:http://www.cnblogs.com/EmptyFS/
* 技 术 群:327360708
*
* 创建日期:2014-07-07
* 文件名称:AdvertisingPositionBll.cs
* 描 述:广告位置管理逻辑类
*
* 修 改 人:
* 修改日期:
* 修改原因:
***********************************************************************/
namespace Solution.Logic.Managers
{
/// <summary>
/// AdvertisingPositionBll逻辑类
/// </summary>
public partial class AdvertisingPositionBll : LogicBase
{
/***********************************************************************
* 自定义函数 *
***********************************************************************/ #region 自定义函数 #region 绑定广告位置下拉列表
/// <summary>
/// 绑定广告位置下拉列表——只显示一级广告位置
/// </summary>
public void BandDropDownList(Page page, FineUI.DropDownList ddl)
{
var dt = DataTableHelper.GetFilterData(GetDataTable(), AdvertisingPositionTable.ParentId, "", AdvertisingPositionTable.Sort, "desc"); //显示值
ddl.DataTextField = AdvertisingPositionTable.Name;
//绑定Id
ddl.DataValueField = AdvertisingPositionTable.Id; //绑定数据源
ddl.DataSource = dt;
ddl.DataBind();
ddl.Items.Insert(, new FineUI.ListItem("请选择广告位置", ""));
ddl.SelectedValue = "";
} /// <summary>
/// 绑定广告位置下拉列表——显示所有
/// </summary>
public void BandDropDownListShowAll(Page page, FineUI.DropDownList ddl)
{
//设置排序
var sortList = new List<string>();
sortList.Add(AdvertisingPositionTable.Depth);
sortList.Add(AdvertisingPositionTable.Sort); //筛选记录
var dt = GetDataTable(false, , null, , , null, sortList); try
{
//整理出有层次感的数据
dt = DataTableHelper.DataTableTidyUp(dt, AdvertisingPositionTable.Id, AdvertisingPositionTable.ParentId, ); ddl.EnableSimulateTree = true; //显示值
ddl.DataTextField = AdvertisingPositionTable.Name;
//绑定Id
ddl.DataValueField = AdvertisingPositionTable.Id;
//数据层次
ddl.DataSimulateTreeLevelField = AdvertisingPositionTable.Depth;
//绑定数据源
ddl.DataSource = dt;
ddl.DataBind();
ddl.SelectedIndex = ; ddl.Items.Insert(, new FineUI.ListItem("请选择广告位置", ""));
ddl.SelectedValue = "";
}
catch (Exception e)
{
// 记录日志
CommonBll.WriteLog("", e);
}
}
#endregion #endregion 自定义函数
}
}

  接口函数与数据加载函数在前面的章节已经讲述过了,这里就不再重复说明

  列表属性绑定,一般指的是页面中列表的列控件、点击事件、翻页事件、排序事件......等各种列表控件事件的绑定,对于翻页与排序事件,我们在父类中已经实现了,所以不用再进行处理,而这里我们要做的功能是,点击列表中的状态项进行更新,比如当前记录的状态是允许该记录显示出来,那么点击后就自动更改为隐藏状态。

  对于这里,我们按下面代码修改一下

 #region 列表属性绑定

         #region 列表按键绑定——修改列表控件属性
/// <summary>
/// 列表按键绑定——修改列表控件属性
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Grid1_PreRowDataBound(object sender, FineUI.GridPreRowEventArgs e)
{
//绑定是否显示状态列
GridRow gr = Grid1.Rows[e.RowIndex];
if (((System.Data.DataRowView)(gr.DataItem)).Row.Table.Rows[e.RowIndex][AdvertisingPositionTable.IsDisplay].ToString() == "")
{
var lbf = Grid1.FindColumn("IsDisplay") as LinkButtonField;
lbf.Icon = Icon.BulletCross;
lbf.CommandArgument = "";
}
else
{
var lbf = Grid1.FindColumn("IsDisplay") as LinkButtonField;
lbf.Icon = Icon.BulletTick;
lbf.CommandArgument = "";
} //绑定是否编辑列
var lbfEdit = Grid1.FindColumn("ButtonEdit") as LinkButtonField;
lbfEdit.Text = "编辑";
lbfEdit.Enabled = MenuInfoBll.GetInstence().CheckControlPower(this, "ButtonEdit");
}
#endregion #region Grid点击事件
/// <summary>
/// Grid点击事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Grid1_RowCommand(object sender, FineUI.GridCommandEventArgs e)
{
GridRow gr = Grid1.Rows[e.RowIndex];
//获取当前点击列的主键ID
object id = gr.DataKeys[]; switch (e.CommandName)
{
case "IsDisplay":
//更新状态
AdvertisingPositionBll.GetInstence().UpdateIsDisplay(this, ConvertHelper.Cint0(id), ConvertHelper.Cint0(e.CommandArgument));
//重新加载
LoadData(); break;
case "ButtonEdit":
//打开编辑窗口
Window1.IFrameUrl = "AdvertisingPositionEdit.aspx?Id=" + id + "&" + MenuInfoBll.GetInstence().PageUrlEncryptStringNoKey(id + "");
Window1.Hidden = false; break;
}
}
#endregion #endregion

  对于AdvertisingPositionBll.GetInstence().UpdateIsDisplay()函数的调用,如果没有细心留意前面章节的朋友,可能会比较奇怪怎么有这个函数,这是因为我们在设计数据库时,所有状态类的字段都会设置为tinyint类型,当逻辑层代码生成模板检测到字段类型为tinyint时,就会生成一个更新状态的函数提供给我们调用,这样我们就无需去编写这些常用的函数了,直接拿来使用即可。

  比较一下这里列表属性绑定后的效果

  对于记录删除函数,一般在删除前我们都必须判断一下,看看该记录是否已给其他表引用了,是的话则不能直接删除(因为直接删掉的话有可能会引起其他表使用时的异常或数据同步查询等问题),另外如果存在图片的也必须先删掉图片,当然图片删除函数我们的逻辑层模板也生成好了,直接引用就可以了。这些都处理好才直接执行记录删除函数删除记录。

  由于我们的广告表未创建,所以这里我们先将广告位置是否给广告表引表的检查注释掉。

         #region 删除记录
/// <summary>
/// 删除记录
/// </summary>
/// <returns></returns>
public override string Delete()
{
//获取要删除的ID
int id = ConvertHelper.Cint0(GridViewHelper.GetSelectedKey(Grid1, true)); //如果没有选择记录,则直接退出
if (id == )
{
return "请选择要删除的记录。";
} try
{
//删除前判断一下
if (AdvertisingPositionBll.GetInstence().Exist(x => x.ParentId == id))
{
return "删除失败,本广告位置下面存在子广告位置,不能直接删除!";
}
//删除前判断一下
//if (InformationBll.GetInstence().Exist(x => x.AdvertisingPosition_Id == id))
//{
// return "删除失败,本广告位置已被信息表的记录引用,不能直接删除!";
//} //删除记录
bll.Delete(this, id); return "删除编号ID为[" + id + "]的数据记录成功。";
}
catch (Exception e)
{
string result = "尝试删除编号ID为[" + id + "]的数据记录失败!"; //出现异常,保存出错日志信息
CommonBll.WriteLog(result, e); return result;
}
}
#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文件,编辑显示的控件

 <f:TextBox runat="server" ID="txtName" Label="位置名称" ShowRedStar="true" Width="250px">
</f:TextBox>
<f:TextBox runat="server" ID="txtKey" Label="关键字" ShowRedStar="true" Width="250px">
</f:TextBox>
<f:DropDownList Label="所属位置选择" AutoPostBack="true" Required="true" CompareType="String"
EnableSimulateTree="true" runat="server" ID="ddlParentId" Width="200px" OnSelectedIndexChanged="ddlParentId_SelectedIndexChanged">
</f:DropDownList>
<f:TextBox Readonly="true" runat="server" ID="txtParent" Label="父Id" EmptyText="对应的父类Id"
Width="100px" Text="">
</f:TextBox>
<f:TextBox runat="server" ID="txtSort" Label="排序" Width="250px" Text=""></f:TextBox>
<f:RadioButtonList ID="rblIsDisplay" Label="是否显示" ColumnNumber="" runat="server"
ShowRedStar="true" Required="true">
<f:RadioItem Text="显示" Value="" Selected="true"/>
<f:RadioItem Text="不显示" Value="" />
</f:RadioButtonList>
<f:FileUpload runat="server" ID="MapImg" Label="位置图" Width="250px" />
<f:Button runat="server" Text="删除位置图" OnClick="BtnDelMapImg_Click"></f:Button>
<f:Image runat="server" ID="imgMap"></f:Image>
<f:FileUpload runat="server" ID="PicImg" Label="默认广告图" Width="250px" />
<f:Button runat="server" Text="删除默认图" OnClick="BtnDelPicImg_Click"></f:Button>
<f:Image runat="server" ID="imgPic"></f:Image>
<f:HiddenField runat="server" ID="hidId" Text=""></f:HiddenField>

  对于编辑页面对应的cs文件,如果页面比较简单的话,我们一般要做的处理就是对对aspx页面的控件进行赋值操作,还有就是存储处理。

  对于AdvertisingPositionEdit.aspx.cs文件,同样我们也是先在加载数据函数中,对页面控件进行赋值操作。

  通过逻辑层的GetModelForCache()函数来读取记录实体(这里要注意的是,如果数据表的记录可能会比较多的时候,我们就不要使用数据缓存功能,这样会加大服务器的负担,我们直接使用GetModel(id, false)函数直接从数据库中读取实体),然后对页面控件逐个赋值。对于下拉列表的绑定,编辑时不建议开启修改,因为修改时编辑人员可能会更改当前节点到其他级别的父类,这样操作需要在保存函数里做相当多的判断处理,增大开发的工作量。

         #region 加载数据
/// <summary>读取数据</summary>
public override void LoadData()
{
int id = ConvertHelper.Cint0(hidId.Text); if (id != )
{
//获取指定ID的广告位置内容
var model = AdvertisingPositionBll.GetInstence().GetModelForCache(x => x.Id == id);
if (model == null)
return; //地址名称
txtName.Text = model.Name;
//给下拉列表赋值
ddlParentId.SelectedValue = model.ParentId + "";
//编辑时不能修改父节点
ddlParentId.Enabled = false;
//设置父ID
txtParent.Text = model.ParentId + "";
//设置排序
txtSort.Text = model.Sort + "";
//KEY
txtKey.Text = model.Keyword;
//给页面图片赋值
if (model.MapImg != null && model.MapImg.Length > )
{
imgMap.ImageUrl = DirFileHelper.GetFilePathPostfix(model.MapImg, "s");
}
else
{
//不存在图片,则隐藏图片控件和图片删除按钮
imgMap.Visible = false;
ButtonDelMapImg.Visible = false;
}
//给页面图片赋值
if (model.PicImg != null && model.PicImg.Length > )
{
imgPic.ImageUrl = DirFileHelper.GetFilePathPostfix(model.PicImg, "s");
}
else
{
//不存在图片,则隐藏图片控件和图片删除按钮
imgPic.Visible = false;
ButtonDelPicImg.Visible = false;
}
//是否显示(状态)
rblIsDisplay.SelectedValue = model.IsDisplay + ""; }
else
{
//新建广告位置时,隐藏图片控件和图片删除按钮
imgMap.Visible = false;
imgPic.Visible = false;
ButtonDelMapImg.Visible = false;
ButtonDelPicImg.Visible = false;
}
} #endregion

  添加删除图片按钮函数,从下列代码中可以看到,删除函数都是调用模板生成的

         #region 删除图片
/// <summary>
/// 删除位置图
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void ButtonDelMapImg_Click(object sender, EventArgs e)
{
AdvertisingPositionBll.GetInstence().DelMapImg(this, ConvertHelper.Cint0(hidId.Text));
//删除后刷新编辑窗口
Response.Redirect(Request.Url.ToString());
} /// <summary>
/// 删除默认图片
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void ButtonDelPicImg_Click(object sender, EventArgs e)
{
AdvertisingPositionBll.GetInstence().DelPicImg(this, ConvertHelper.Cint0(hidId.Text));
//删除后刷新编辑窗口
Response.Redirect(Request.Url.ToString());
}
#endregion

  进入保存操作时,一般我们要先对输入的数据进行检查,检查必填项是否为空,检查指定项在数据库中是否存在重复项等内容,然后获取或创建编辑实体,跟着检查相关项是否有修改,有的话保存成功后需要同步修改其他关联表对应的字段,接着是读取页面控件值对实体进行赋值操作,如果有图片上传的,则调用上传方法上传图片,再然后就是保存实体,同步更新关联表字段。

  首先检查检查必填项是否为空,检查指定项在数据库中是否存在重复项等内容

                 #region 数据验证

                 if (string.IsNullOrEmpty(txtName.Text.Trim()))
{
return txtName.Label + "不能为空!";
}
var sName = StringHelper.FilterSql(txtName.Text, true);
if (AdvertisingPositionBll.GetInstence().Exist(x => x.Name == sName && x.Id != id))
{
return txtName.Label + "已存在!请重新输入!";
}
if (string.IsNullOrEmpty(txtKey.Text.Trim()))
{
return txtKey.Label + "不能为空!";
}
var sKeyword = StringHelper.FilterSql(txtKey.Text, true);
if (AdvertisingPositionBll.GetInstence().Exist(x => x.Keyword == sKeyword && x.Id != id))
{
return txtKey.Label + "已存在!请重新输入!";
} #endregion

  在开发时要注意的是,使用lambda表达式传递条件时,必须先计算出值后,将存储值的变量放到lambda表达式中比较,而不能将计算的表达式作为值放在lambda表达式中比较,这样会出错的。

  对相关项进行检查完毕后,跟着就是进行赋值操作,获取页面控件值进行SQL注入过滤或XSS过滤后,将值赋给实体。

  对于页面控件值的获取,字符串类型一般都会使用StringHelper.Left(页面控件, 截取长度)函数来获取,让输入到数据库的字段值自动去掉两旁空格,并进行XSS过滤后,截取数据表字段规定的大小后存储过来,避免相关人员录入过长数据,而对于需要录入特殊符号的字段,可以使用StringHelper.Left(页面控件, 截取长度, true, false)函数来获取,这样就只进行SQL注入过滤,而不进行XSS过滤,具体请大家查看该函数,里面有详细注释。而对于数值型的则使用相关函数进行转换。

                 #region 赋值
//定义是否更新其他关联表变量
bool isUpdate = false; //读取当前地址信息
var model = new AdvertisingPosition(x => x.Id == id); //判断是否更新关联表
if (model.Id > && sName != model.Name)
isUpdate = true; //设置名称
model.Name = StringHelper.Left(txtName.Text, );
//KEY
model.Keyword = StringHelper.Left(txtKey.Text, );
//对应的父类id
model.ParentId = ConvertHelper.Cint0(txtParent.Text);
//由于限制了编辑时不能修改父节点,所以这里只对新建记录时处理
if (id == )
{
//设定当前的深度与设定当前的层数级
if (model.ParentId == )
{
//设定当前的层数级
model.Depth = ;
}
else
{
//设定当前的层数
model.Depth = ConvertHelper.Cint0(AdvertisingPositionBll.GetInstence().GetFieldValue(ConvertHelper.Cint0(ddlParentId.SelectedValue), AdvertisingPositionTable.Depth)) + ;
} //限制分类层数只能为2层
if (model.Depth > )
{
return "广告位置只能创建2层分类!";
}
}
//设置排序
if (txtSort.Text == "")
{
model.Sort = AdvertisingPositionBll.GetInstence().GetSortMax(model.ParentId) + ;
}
else
{
model.Sort = ConvertHelper.Cint0(txtSort.Text);
}
//设定当前项是否显示
model.IsDisplay = ConvertHelper.StringToByte(rblIsDisplay.SelectedValue); //广告宽与高
model.Width = ConvertHelper.Cint0(txtWidth.Text);
model.Height = ConvertHelper.Cint0(txtHeight.Text); //添加最后修改人员
model.Manager_Id = OnlineUsersBll.GetInstence().GetManagerId();
model.Manager_CName = OnlineUsersBll.GetInstence().GetManagerCName();
model.AddDate = DateTime.Now; #endregion

  如果页面需要上传图片的,则必须先在系统管理=》基础设置=》上传配置管理中,添加一项新的配置,取得新建的配置Id后,再使用图片上传方法来上传图片。具体上传类的使用我会在后面的章节单独讲解。

  代码中绑定好对应的Id

  最后是将实体保存到数据库,以及同步更新关联表字段,由于广告表未创建,所以暂时注释掉代码。

  接下来要做的还是菜单注册与权限绑定操作,这里就不再继续重复了。

  最终编辑页面实现效果:

  上面内容看起来好像非常多很复杂的样子,实际上只要你做过几个例子,然后熟悉本框架的开发模式后就会感觉简单多了,整个操作来看,编码部分相对来说比较少,且绝大部分都是调用已生成好的模板函数,也就是说只要你熟悉了模板函数,想实现什么样的功能都不是很难,同时也不用自己编写大量的逻辑层以及数据层代码,一键生成。想轻松的使用本框架开发新功能,必须学会FineUI插件的相关调用,FineUI官方有在线示例,都比较简单。其实只要你将FineUI的控件属性,在页面中直接修改后刷新页面,查看其变化,逐个测试过后你就基本上掌握了,非常简单,我也是这样学习的。

  整个操作所花费的时间更多是用在数据库表单的设计、UI的绘制,以及页面开发完成后在后端权限模块进行注册绑定。

  使用本框架开发,更多的是让开发人员从复制粘贴工作中解放出来,不用编写大量的底层重复函数,更多的关注UI的制作以及业务逻辑设计。因为底层模块会将日志、安全检查、常用函数.....等功能已经帮我们实现了。

由于框架不是非常成熟,很多朋友不是用来学习而是直接用到项目中,但不熟悉框架引起不少小问题,所以停止提供下载,有需要学习的可以到群共享里下,不便之处敬请谅解。

 版权声明:

  本文由AllEmpty原创并发布于博客园,欢迎转载,未经本人同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。如有问题,可以通过1654937@qq.com 联系我,非常感谢。

  发表本编内容,只要主为了和大家共同学习共同进步,有兴趣的朋友可以加加Q群:327360708 ,大家一起探讨。

  更多内容,敬请观注博客:http://www.cnblogs.com/EmptyFS/

从零开始编写自己的C#框架(21)——添加分类类型页面的更多相关文章

  1. 从零开始编写自己的C#框架(1)——前言

    记得十五年前自学编程时,拿着C语言厚厚的书,想要上机都不知道要用什么编译器来执行书中的例子.十二年前在大学自学ASP时,由于身边没有一位同学和朋友学习这种语言,也只能整天混在图收馆里拼命的啃书.而再后 ...

  2. 从零开始编写自己的C#框架 ---- 系列文章

    目录: 从零开始编写自己的C#框架(1)——前言从零开始编写自己的C#框架(2)——开发前的准备工作从零开始编写自己的C#框架(3)——开发规范从零开始编写自己的C#框架(4)——文档编写说明从零开始 ...

  3. 从零开始编写自己的C#框架(17)——Web层后端首页

    后端首页是管理员登陆后进入的第一个页面,主要是显示当前登陆用户信息.在线人数.菜单树列表.相关功能按键和系统介绍.让管理员能更方便的找到息想要的内容. 根据不同系统的需要,首页会显示不同的内容,比如显 ...

  4. 从零开始编写自己的C#框架(26)——小结

    一直想写个总结,不过实在太忙了,所以一直拖啊拖啊,拖到现在,不过也好,有了这段时间的沉淀,发现自己又有了小小的进步.哈哈...... 原想框架开发的相关开发步骤.文档.代码.功能.部署等都简单的讲过了 ...

  5. 从零开始编写自己的C#框架(25)——网站部署

    导航 1.关掉访问保护 2.发布网站 3.复制网站到服务器 4.添加新网站 5.设置网站访问权限 6.设置文件夹访问权限 7.控制可更新文件夹执行权限 8.设置“应用程序池”.net版本与模式 9.附 ...

  6. 从零开始编写自己的C#框架(20)——框架异常处理及日志记录

    最近很忙,杂事也多,所以开发本框架也是断断续续的,终于在前两天将前面设定的功能都基本完成了,剩下一些小功能遗漏的以后发现再补上.接下来的章节主要都是讲解在本框架的基础上进行开发的小巧. 本框架主要有四 ...

  7. 从零开始编写自己的C#框架(15)——Web层后端登陆功能

    对于一个后端管理系统,最重要内容之一的就是登陆页了,无论是安全验证.用户在线记录.相关日志记录.单用户或多用户使用帐号控制等,都是在这个页面进行处理的. 1.在解决方案中创建一个Web项目,并将它设置 ...

  8. 从零开始编写自己的C#框架(11)——创建解决方案

    这段时间一直在充电,拜读了园子中大神们的博文(wayfarer的<设计之道>.TerryLee的<.NET设计模式系列文章>.卡奴达摩的<设计模式>还有其他一些零散 ...

  9. 从零开始编写自己的C#框架(2)——开发前准备工作

    没想到写了个前言就受到很多朋友的支持,大家的推荐就是我最大的动力(推荐得我热血沸腾,大家就用推荐来猛砸我吧O^-^O),谢谢大家支持. 其实框架开发大家都知道,不过要想写得通俗点,我个人觉得还是挺吃力 ...

随机推荐

  1. App开发:模拟服务器数据接口 - MockApi

    为了方便app开发过程中,不受服务器接口的限制,便于客户端功能的快速测试,可以在客户端实现一个模拟服务器数据接口的MockApi模块.本篇文章就尝试为使用gradle的android项目设计实现Moc ...

  2. SQLSERVER走起微信公众帐号全新改版 全新首页

    SQLSERVER走起微信公众帐号全新改版 全新首页 今天,SQLSERVER走起微信公众帐号增加了首页功能 虽然还是订阅号,不过已经对版面做了比较大的修改,希望各位亲用得放心.用得安心O(∩_∩)O ...

  3. js中参数不对应问题

    因为js是一种弱类型的编程语言,对数据类型的要求没有其他编程语言的要求严格,所以在定义函数的时候不需要像java和C#一样对其传入参数的类型进行定义.那么传入参数的个数有没有影响呢?今天小猪就做了个实 ...

  4. SQL Server 2014 新特性——内存数据库

    SQL Server 2014 新特性——内存数据库 目录 SQL Server 2014 新特性——内存数据库 简介: 设计目的和原因: 专业名词 In-Memory OLTP不同之处 内存优化表 ...

  5. CRL快速开发框架系列教程十三(嵌套查询)

    本系列目录 CRL快速开发框架系列教程一(Code First数据表不需再关心) CRL快速开发框架系列教程二(基于Lambda表达式查询) CRL快速开发框架系列教程三(更新数据) CRL快速开发框 ...

  6. JAVA构造时成员初始化的陷阱

    让我们先来看两个类:Base和Derived类.注意其中的whenAmISet成员变量,和方法preProcess(). 情景1:(子类无构造方法) class Base { Base() { pre ...

  7. 3种web会话管理的方式

    http是无状态的,一次请求结束,连接断开,下次服务器再收到请求,它就不知道这个请求是哪个用户发过来的.当然它知道是哪个客户端地址发过来的,但是对于我们的应用来说,我们是靠用户来管理,而不是靠客户端. ...

  8. Android中Fragment与Activity之间的交互(两种实现方式)

    (未给Fragment的布局设置BackGound) 之前关于Android中Fragment的概念以及创建方式,我专门写了一篇博文<Android中Fragment的两种创建方式>,就如 ...

  9. MyBatis3.2从入门到精通第一章

    第一章一.引言mybatis是一个持久层框架,是apache下的顶级项目.mybatis托管到goolecode下,再后来托管到github下.(百度百科有解释)二.概述mybatis让程序将主要精力 ...

  10. Unity插件之plyGame教程:DiaQ对话系统

    本文为孤月蓝风编写,转载请注明出处:http://fengyu.name/?cat=game&id=296 DiaQ是plyGame旗下的一款对话及任务系统.拥有可视化的对话及任务编辑器,能够 ...