2018年11月18日 23:32
原创作品,转载时请务必以超链接形式标明文章原始出处,否则将追究法律责任。

前段时间,有个人想做一个后台管理程序,来管理他的Helo App。单表增删改查,一个登录界面,我一口报价600元,小伙子答应了。

看一下这个后台管理是啥样子。

20181119013152.png

这个是登录界面,没什么说的,再看一下主界面。

20181118232425.png

一个简单的根据用户名,性别查询。能够创建新用户,修改用户,删除用户。

那么这么样一个需求,用什么来做呢?首先用户肯定的说不能做成cs,排除winform and wpf。现在选择的余地还有asp.net webforms和asp.net mvc,或者node.js。选择谁呢,考虑再三,我觉得还是webforms做起来最快,直接服务端控件搞起。有的人说这个webforms过时了,存在即合理,有什么过时的,钱挣到手再说。

看一下程序结构,如下。

20181119013221.png

看起来是如此的简单,一个登录一个Default.aspx,接下来我们看一下主页面吧。

(1)先是查询条件,用bootstrap的panel组件包起来。

<div class="panel panel-default">
    <div class="panel-body">
        <div class="row row-line">
            <div class="col-md-1">
                <label>用户名:</label>
            </div>
            <div class="col-md-3">
                <asp:TextBox runat="server" MaxLength="20" ID="txt_UserName" CssClass="form-control" AutoComplete="off"></asp:TextBox>
            </div>
            <div class="col-md-2 text-right">
                <label>性别:</label>
            </div>
            <div class="col-md-2">
                <asp:DropDownList ID="ddl_Sex" runat="server" DataValueField="SexId" DataTextField="SexDisplay" CssClass="form-control"></asp:DropDownList>
            </div>
            <div class="col-md-1">
                <asp:Button runat="server" Text="查询" ID="btn_Search" CssClass="btn btn-success" OnClick="btn_Search_Click" CausesValidation="false" />
            </div>
            <div class="col-md-2" style="text-align: right">
                <button type="button" onclick="showCreateModal()" class="btn btn-primary">创建用户</button>
            </div>
            <div class="col-md-1">
                <asp:Button ID="btn_LogOut" runat="server" Text="注销" OnClick="btn_LogOut_Click" CssClass="btn btn-warning" />
            </div>
        </div>
    </div>
</div>

(2)GridView绑定数据

<div class="margin-top-10">
    <asp:GridView ID="gv_UserList"
        CssClass="table table-striped table-bordered table-condensed table-hover"
        runat="server"
        ShowHeader="true"
        AutoGenerateColumns="False"
        DataKeyNames="UserCode"
        OnRowCreated="gv_UserList_RowCreated"
        OnRowDeleting="gv_UserList_RowDeleting"
        OnRowDataBound="gv_UserList_RowDataBound">
        <Columns>
            <asp:TemplateField HeaderText="照片" ItemStyle-HorizontalAlign="Center" HeaderStyle-Width="80px">
                <ItemTemplate>
                    <img class="lazy" style="width: 50px; height: 50px" data-original="<%#DataBinder.Eval(Container.DataItem,"HeadImage") %>" />
                </ItemTemplate>
            </asp:TemplateField>
            <asp:BoundField DataField="UserCode" HeaderText="用户名" SortExpression="UserCode" HeaderStyle-Width="200px" />
            <asp:BoundField DataField="UserPwd" HeaderText="密码" HeaderStyle-Width="120px" />
            <asp:BoundField DataField="Sex" HeaderText="性别" SortExpression="Sex" HeaderStyle-Width="80px" />
            <asp:BoundField DataField="Birthday" HeaderText="出生日期" DataFormatString="{0:yyyy-MM-dd}" HeaderStyle-Width="120px" />
            <asp:BoundField DataField="GenerateNum" HeaderText="生成码" HeaderStyle-Width="70px" />
            <asp:BoundField DataField="Source" HeaderText="注册来源" HeaderStyle-Width="70px" />
            <asp:BoundField DataField="CreateDate" HeaderText="注册日期" SortExpression="CreateDate" DataFormatString="{0:yyyy-MM-dd HH:mm:ss}" HeaderStyle-Width="130px" />
            <asp:TemplateField HeaderText="编辑" HeaderStyle-Width="40px">
                <ItemTemplate>
                    <button type="button" id="btn_Edit" class="btn btn-info" onclick="<%# "javascript:showModifyModal('"+
                            DataBinder.Eval(Container.DataItem,"UserCode")+"','"+
                            DataBinder.Eval(Container.DataItem,"UserPwd")+"','"+
                            DataBinder.Eval(Container.DataItem,"Sex")+"','"+
                            DataBinder.Eval(Container.DataItem,"Birthday")+"','"+
                            DataBinder.Eval(Container.DataItem,"HeadImageID")+"','"+
                            DataBinder.Eval(Container.DataItem,"HeadImage")+"')"%>">
                        编辑</button>
                </ItemTemplate>
            </asp:TemplateField>
            <asp:CommandField HeaderText="删除" DeleteText="删除" ShowDeleteButton="True" ButtonType="Button" ControlStyle-CssClass="btn btn-danger" HeaderStyle-Width="40px" />
        </Columns>
        <EmptyDataTemplate>
            <asp:Label ID="Label1" Text="无数据" runat="server" ForeColor="Red"></asp:Label>
        </EmptyDataTemplate>
    </asp:GridView>
</div>
<webdiyer:AspNetPager
    ID="pager_UserList"
    OnPageChanging="pager_UserList_PageChanging"
    runat="server"
    HorizontalAlign="Center"
    PagingButtonSpacing="0"
    NumericButtonCount="8"
    Width="100%"
    ShowCustomInfoSection="Left"
    PageIndexBoxStyle="width:19px"
    FirstPageText="【首页】"
    LastPageText="【尾页】"
    NextPageText="【下一页】"
    PrevPageText="【上一页】"
    NumericButtonTextFormatString="【{0}】"
    TextAfterPageIndexBox="页"
    TextBeforePageIndexBox="转到第"
    CustomInfoHTML="共&nbsp;<font color='red'><b>%RecordCount%</b></font>&nbsp;条记录&nbsp;&nbsp;&nbsp;共 <font color='red'><b>%PageCount%</b></font>&nbsp页">
</webdiyer:AspNetPager>

这里第一列是用户图像列,还有个编辑列,我将其做成模板列,修改按钮会调用一个js方法弹出修改界面。在这里注意了,分页使用杨涛的AspNetPager,省时省力。在这一步,大家先记住GridView上的三个事件,RowCreated,RowDeleting,RowDataBound。顾名思义,分别是行创建结束,正要删除行,行数据绑定完成。


OK,我们接下来看一下后端cs代码。

protected void Page_Load(object sender, EventArgs e)
{
    if (Session["UserName"] == null)
    {
        Response.Redirect("~/Login.aspx");
        return;
    }

    ProcessRequest();

    if (!IsPostBack)
    {
        InitDropdownList();
        InitData();
        InitImageList();
    }
}

在PageLoad事件中判断有没有登录,绑定下拉列表选项,初始化GridView数据。

private void ProcessRequest()
{
    if (Request["action"] == "update")
    {
        DoUpdateHandler();
    }
    else if (Request["action"] == "create")
    {
        DoCreateHandler();
    }
}

private void InitDropdownList()
{
    var sexList = new List<SexEntity>
    {
        new SexEntity{ SexId=-1, SexDisplay="---全部---" },
        new SexEntity{ SexId=1, SexDisplay="女" },
        new SexEntity{ SexId=0, SexDisplay="男" }
    };

    ddl_Sex.DataSource = sexList;
    ddl_Sex.DataBind();
    ddl_Sex.SelectedIndex = 0;

    sexList[0].SexDisplay = "---请选择---";
    ddl_SetupSex.DataSource = sexList;
    ddl_SetupSex.DataBind();
    ddl_SetupSex.SelectedIndex = 0;
}

private void InitData()
{
    string userName = txt_UserName.Text.Trim();
    int userSex = Convert.ToInt32(ddl_Sex.SelectedValue);
    int pageIndex = pager_UserList.CurrentPageIndex - 1;
    int pageSize = pager_UserList.PageSize;

    using (HeloEntities heloEntities = new HeloEntities())
    {
        IQueryable<Users> query = heloEntities.Users;
        if (!string.IsNullOrEmpty(userName))
        {
            query = query.Where(q => q.UserCode.Contains(userName));
        }

        if (userSex >= 0)
        {
            query = query.Where(q => q.Sex == userSex);
        }

        query = query.Where(q => q.IsDisable == 0);
        query = query.OrderByDescending(q => q.CreateDate);

        var pagedData = new PagedList<Users>(query, pageIndex, pageSize);
        gv_UserList.DataSource = pagedData.ToList().Select(p =>
        {
            return new UserModel
            {
                UserCode = p.UserCode,
                UserPwd = p.UserPwd,
                Birthday = p.Birthday,
                HeadImage = p.AD_DATA_DICTIONARY?.DictionaryValue,
                HeadImageID = p.AD_DATA_DICTIONARY?.DictionaryCode,
                Sex = p.Sex,
                Source = p.Source,
                GenerateNum = p.GenerateNum,
                CreateDate = p.CreateDate.HasValue ? p.CreateDate.Value.ToString() : string.Empty
            };
        }).ToList();

        pager_UserList.RecordCount = pagedData.TotalCount;
        pager_UserList.CurrentPageIndex = 0;
        gv_UserList.DataBind();
    }
}

private void InitImageList()
{
    if (Request["action"] == "getImageList")
    {
        using (HeloEntities heloEntities = new HeloEntities())
        {
            Response.Clear();
            Response.ContentType = "application/json; charset=utf-8";
            var imageList = heloEntities.AD_DATA_DICTIONARY.ToList();
            Response.Write(JsonConvert.SerializeObject(imageList.Select(i => new { Code = i.DictionaryCode, Value = i.DictionaryValue }).ToList()));
            Response.End();
        }
    }
}

当时小伙给了我数据库,看起来命名比较烂。为了图快,那我必须是EF,上面这些不用说大家都知道,我们看一下js部分。

function showModifyModal(userCode, userPwd, sex, birthDay, imageId, imageUrl) {
    reset();
    $('#<%=txt_SetupUserName.ClientID%>').attr('readonly', true);
    $('#<%=txt_PassWord.ClientID%>').val(userPwd);
    $('#hfd_UserCode').val(userCode);
    $('#<%=txt_SetupUserName.ClientID%>').val(userCode);
    $('#<%=ddl_SetupSex.ClientID%>').val(!sex ? "-1" : sex);
    $('#<%=txt_BirthDay.ClientID%>').val(birthDay);
    $('#hfd_ImageId').val(imageId);
    $('#img_User').attr('src', imageUrl);
    $('#userModifyModal').modal('show');
}

这个是弹出修改界面代码,说了这么久,还没见到修改界面。

20181119020026.png

这是一个bootstrap modal页,点击选择图像,可以选择自己喜欢的图像。

20181119020331.png

就是一堆海里的动物,不知道为啥用户这么喜欢海里的东西,看一下这个弹出选择动物的这个界面代码。

<div class="modal fade" id="userImageModal"
    tabindex="-1"
    role="dialog"
    data-backdrop="true"
    aria-labelledby="myImageModalLabel"
    aria-hidden="true">
    <div class="modal-dialog" style="width: 500px;">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
                <h4 class="modal-title" id="myImageModalLabel">用户图像选择</h4>
            </div>
            <div class="modal-body">
                <div class="row">
                    <div class="col-md-12" id="div_ImageList">
                    </div>
                </div>
            </div>
            <div class="modal-footer">
                <button type="button" class="btn btn-warning" data-dismiss="modal">关闭</button>
            </div>
        </div>
    </div>
    <!-- /.modal-content -->
</div>
$.ajax({
    url: 'default.aspx?action=getImageList',
    type: 'get',
    dataType: 'json',
    success: function (data) {
        if (data && data.length > 0) {
            $.each(data, function (obj) {
                $("#div_ImageList").append("<div class='col-md-2'><img style='width:60px;height:60px;padding:2px;cursor:pointer' tag='" + $(this)[0].Code + "' src='" + $(this)[0].Value + "'></img></div>");
            });

            $("#div_ImageList img").mouseover(function () {
                $(this).css("background-color", "#2aabd2");
            });

            $("#div_ImageList img").mouseout(function () {
                $(this).css("background-color", "");
            });

            $("#div_ImageList img").click(function () {
                $('#userImageModal').modal('hide');
                $('#img_User').attr('src', $(this).attr('src'));
                $('#hfd_ImageId').val($(this).attr('tag'));
            });
        }
    }
});

请求到图片以后,加载到div(#div_ImageList)中。

OK,最后再看一下最早提到的那三个事件。

protected void gv_UserList_RowCreated(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        ControlCollection ctrlCollection = e.Row.Cells[e.Row.Cells.Count - 1].Controls;
        foreach (var ctrl in ctrlCollection)
        {
            if (ctrl is Button && (ctrl as Button).Text == "删除")
            {
                (ctrl as Button).Attributes.Add("onclick", "if(!window.confirm('确定删除吗?')) return;");
                break;
            }
        }
    }
}

protected void gv_UserList_RowDeleting(object sender, GridViewDeleteEventArgs e)
{
    string userCode = gv_UserList.DataKeys[e.RowIndex].Value.ToString();
    using (HeloEntities heloEntities = new HeloEntities())
    {
        var user = heloEntities.Users.FirstOrDefault(u => u.UserCode == userCode);
        if (user != null)
        {
            user.IsDisable = 1;
            heloEntities.SaveChanges();
            InitData();
        }
    }
}

protected void gv_UserList_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.DataItem == null) return;

    UserModel userModel = e.Row.DataItem as UserModel;

    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        if (userModel.Sex == 1)
        {
            e.Row.Cells[3].Text = "女";
        }
        else if (userModel.Sex == 0)
        {
            e.Row.Cells[3].Text = "男";
        }
        else
        {
            e.Row.Cells[3].Text = "未知";
        }
    }
}

第一个是为了给删除按钮加confirm,第二个是删除该行数据的时候拿到这行数据的key:UserCode,注意GridView的DataKeyNames,就是设置Row Key的。第三个事件是该行数据绑定完成后触发,这时我们可以拿到该行绑定的对象,在这里就是为了转换男女显示。

好的,今天就到这里,只是想说任何东西存在就有使用的价值,并不是webforms就一文不值,微软就要放弃他,有时候他也能为我们挣些零花钱。

发表评论
匿名  
用户评论

匿名游客

2018年11月22日 18:36
Webforms这个技术太老了,性能不好,别用了。以前有个系统后来挂掉了,就是因为用的是都是服务器控件,特别吃内存。

匿名游客

2018年11月19日 14:35
楼主你这个钱挣得开心啊,这么点东西用了多久?