T O P

[资源分享]     篇(18)-Asp.Net Core入门实战-文章管理之文章内容管理(下拉框二级结构递归)

  • By - 楼主

  • 2022-11-21 16:04:22
  • 篇(18)-Asp.Net Core入门实战-文章管理之文章内容管理(下拉框二级结构递归实现)

    文章管理是CMS系统的核心表之一,存储文章内容,特点就是字段端,属性多,比如是否标识为热点、推荐等属性,是否发布,类别,SEO关键字等。我们本章讲解文章内容的增删改查。

    (1).文章Sql表结构设计

    CREATE TABLE [dbo].[Article](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [CategoryId] [int] NOT NULL,
    [Title] [varchar](128) NOT NULL,
    [ImageUrl] [varchar](128) NULL,
    [Content] [text] NULL,
    [ViewCount] [int] NOT NULL,
    [Sort] [int] NOT NULL,
    [Author] [varchar](64) NULL,
    [Source] [varchar](128) NULL,
    [SeoTitle] [varchar](128) NULL,
    [SeoKeyword] [varchar](256) NULL,
    [SeoDescription] [varchar](512) NULL,
    [AddManagerId] [int] NOT NULL,
    [AddTime] [datetime] NOT NULL,
    [ModifyManagerId] [int] NULL,
    [ModifyTime] [datetime] NULL,
    [IsTop] [bit] NOT NULL,
    [IsSlide] [bit] NOT NULL,
    [IsRed] [bit] NOT NULL,
    [IsPublish] [bit] NOT NULL,
    [IsDeleted] [bit] NOT NULL,
    CONSTRAINT [PK_ARTICLE] PRIMARY KEY NONCLUSTERED
    (
    [Id] ASC
    )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
    ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
    GO
    SET ANSI_PADDING OFF
    GO
    ALTER TABLE [dbo].[Article] ADD DEFAULT (getdate()) FOR [AddTime]
    GO
    ALTER TABLE [dbo].[Article] ADD DEFAULT ((0)) FOR [IsTop]
    GO
    ALTER TABLE [dbo].[Article] ADD DEFAULT ((0)) FOR [IsSlide]
    GO
    ALTER TABLE [dbo].[Article] ADD DEFAULT ((0)) FOR [IsRed]
    GO
    ALTER TABLE [dbo].[Article] ADD DEFAULT ((0)) FOR [IsPublish]
    GO
    ALTER TABLE [dbo].[Article] ADD DEFAULT ((0)) FOR [IsDeleted]
    GO
    ALTER TABLE [dbo].[Article] WITH CHECK ADD CONSTRAINT [FK_ARTICLE_RELATIONS_ARTICLEC] FOREIGN KEY([CategoryId])
    REFERENCES [dbo].[ArticleCategory] ([Id])
    GO
    ALTER TABLE [dbo].[Article] CHECK CONSTRAINT [FK_ARTICLE_RELATIONS_ARTICLEC]
    GO

     

    那么对应的Article Model代码如下:

    public class Article
    {
    /// <summary>
    /// 主键
    /// </summary>
    [Key]
    public Int32 Id { get; set; }
    /// <summary>
    /// 分类ID
    /// </summary>
    [Required]
    public Int32 CategoryId { get; set; }
    /// <summary>
    /// 文章标题
    /// </summary>
    [Required]
    public String Title { get; set; }
    /// <summary>
    /// 图片地址
    /// </summary>
    public String ImageUrl { get; set; }
    /// <summary>
    /// 文章内容
    /// </summary>
    public String Content { get; set; }
    /// <summary>
    /// 浏览次数
    /// </summary>
    [Required]
    public Int32 ViewCount { get; set; }
    /// <summary>
    /// 排序
    /// </summary>
    [Required]
    public Int32 Sort { get; set; }
    /// <summary>
    /// 作者
    /// </summary>
    public String Author { get; set; }
    /// <summary>
    /// 来源
    /// </summary>
    public String Source { get; set; }
    /// <summary>
    /// SEO标题
    /// </summary>
    public String SeoTitle { get; set; }
    /// <summary>
    /// SEO关键字
    /// </summary>
    public String SeoKeyword { get; set; }
    /// <summary>
    /// SEO描述
    /// </summary>
    public String SeoDescription { get; set; }
    /// <summary>
    /// 添加人ID
    /// </summary>
    [Required]
    public Int32 AddManagerId { get; set; }
    /// <summary>
    /// 添加时间
    /// </summary>
    [Required]
    public DateTime AddTime { get; set; }
    /// <summary>
    /// 修改人ID
    /// </summary>
    public Int32? ModifyManagerId { get; set; }
    /// <summary>
    /// 修改时间
    /// </summary>
    public DateTime? ModifyTime { get; set; }
    /// <summary>
    /// 是否置顶
    /// </summary>
    public Boolean IsTop { get; set; }
    /// <summary>
    /// 是否轮播显示
    /// </summary>
    public Boolean IsSlide { get; set; }
    /// <summary>
    /// 是否热门
    /// </summary>
    public Boolean IsRed { get; set; }
    /// <summary>
    /// 是否发布
    /// </summary>
    public Boolean IsPublish { get; set; }
    /// <summary>
    /// 是否删除
    /// </summary>
    [Required]
    public Boolean IsDeleted { get; set; }
    }

     

    (2).视图Create代码

    (2.1)视图代码

    考虑到要同时上传图片,注意form表单的额 enctype类型;

    @{ ViewData["Title"] = "新建文章"; }
    @model Article
    <form action="/Article/Create" method="post" enctype="multipart/form-data">
    @Html.AntiForgeryToken()
    <div>
    <label asp-for="Title">标题</label>
    <div>
    <input type="text" asp-for="Title" name="Title" placeholder="请输入标题">
    </div>
    </div>
    <div>
    <label asp-for="CategoryId">文章类型</label>
    <div>
    @Html.DropDownList("ddl_CategoryId", ViewBag.database as IEnumerable<SelectListItem>)
    </div>
    </div>
    <div>
    <label>设置</label>
    <div>
    @*@Html.CheckBox("IsTop") 置顶
    @Html.CheckBox("IsRed") 热点
    @Html.CheckBox("IsSlide") 幻灯*@
    <input type="checkbox" name="IsTop" asp-for="IsTop" />置顶
    <input type="checkbox" name="IsRed" asp-for="IsRed"/>热点
    <input type="checkbox" name="IsSlide" asp-for="IsSlide" />幻灯
    </div>
    </div>
    <div>
    <label asp-for="ImageUrl">文章首页图</label>
    <div>
    <input type="file" asp-for="ImageUrl" name="ImageUrl"/>
    </div>
    </div>
    <div>
    <label asp-for="Content">内容</label>
    <div>
    <textarea placeholder="内容" asp-for="Content" name="Content" cols="30" rows="10"></textarea>
    </div>
    </div>
    <div>
    <label asp-for="Sort">排序</label>
    <div>
    <input type="text" placeholder="排序" asp-for="Sort" name="Sort" />
    </div>
    </div>
    <div>
    <label asp-for="ViewCount">点击量</label>
    <div>
    <input type="text" placeholder="点击量" asp-for="ViewCount" name="ViewCount" />
    </div>
    </div>
    <div>
    <label asp-for="IsPublish">是否发布</label>
    <div>
    <select asp-for="IsPublish" name="IsPublish" class="IsPublish">
    <option value="False"></option>
    <option value="True" selected></option>
    </select>
    </div>
    </div>
    <div>
    <label asp-for="Author">作者</label>
    <div>
    <input type="text" asp-for="Author" name="Author" placeholder="作者名">
    </div>
    </div>
    <div>
    <label asp-for="Source">来源</label>
    <div>
    <input type="text" asp-for="Source" name="Source" placeholder="文章来源">
    </div>
    </div>
    <div>
    <label asp-for="SeoTitle">SEO标题</label>
    <div>
    <input type="text" asp-for="SeoTitle" name="SeoTitle" placeholder="SEO标题">
    </div>
    </div>
    <div>
    <label asp-for="SeoKeyword">SEO关键词</label>
    <div>
    <input type="text" asp-for="SeoKeyword" name="SeoKeyword" placeholder="SEO关键词">
    </div>
    </div>
    <div>
    <label asp-for="SeoDescription">SEO摘要描述</label>
    <div>
    <input type="text" asp-for="SeoDescription" name="SeoDescription" placeholder="SEO摘要描述">
    </div>
    </div>
    <div>
    <div>
    <button type="submit">确定</button>
    <button type="reset">重置</button>
    </div>
    </div>
    </form>

     

    (2.2)视图中的下拉框的实现方式(递归和循环嵌套)

    我想在添加文章时,实现一个具有二级层次结构的下拉框,如上图所示。所以,在对下拉框进行数据绑定时,就要费点功夫,上个章节讲文章类别管理时,的表结构就一个,分类都存在一张表中,所以要进行递归的获取子菜单或者通过循环嵌套来实现。

    递归的主要核心函数为:

    /// <summary>
    /// 递归函数,实现获取子菜单
    /// </summary>
    /// <param name="lists">递归前的列表</param>
    /// <param name="newlists">递归后的新列表</param>
    /// <param name="parentId">父Id</param>
    /// <returns></returns>
    public static List<CategorySelectItemListView> GetChildCategory(List<CategorySelectItemListView> lists, List<CategorySelectItemListView> newlists, int parentId)
    {
    newlists = new List<CategorySelectItemListView>();
    List<CategorySelectItemListView> tempList = lists.Where(c => c.ParentId == parentId).ToList();
    for (int i = 0; i < tempList.Count; i++)
    {
    CategorySelectItemListView category = new CategorySelectItemListView();
    category.Id = tempList[i].Id;
    category.ParentId = tempList[i].ParentId;
    category.Title = tempList[i].Title;
    category.Children = GetChildCategory(lists, newlists, category.Id);
    newlists.Add(category);
    }
    return newlists;
    }
    
    
    /// <summary>
    /// 循环嵌套,实现获取子菜单
    /// </summary>
    /// <param name="lists">循环遍历前的列表</param>
    /// <returns></returns>
    public static List<CategorySelectItemListView> GetChildCategory(List<CategorySelectItemListView> lists)
    {
    List<CategorySelectItemListView> categorylist = new List<CategorySelectItemListView>();
    for (int i = 0; i < lists.Count; i++)
    {
    if (0 == lists[i].ParentId)
    categorylist.Add(lists[i]);
    for (int j = 0; j < lists.Count; j++)
    {
    if (lists[j].ParentId == lists[i].Id)
    lists[i].Children.Add(lists[j]);
    }
    }
    return categorylist;
    }

     

    然后在Create和Edit的Action中去绑定对应的下拉菜单即可。

    注意:List<CategorySelectItemListView> 集合的CategorySelectItemListView,这个是新建的ViewModel对象,用来专门绑定下拉菜单使用,其代码如下:

    public class CategorySelectItemListView
    {
    public int Id { get; set; }
    public string Title { get; set; }
    public int ParentId { get; set; }
    public List<CategorySelectItemListView> Children { get; set; }
    public CategorySelectItemListView()
    {
    Children = new List<CategorySelectItemListView>();
    }
    
    public CategorySelectItemListView(int id,string title,int parentid)
    {
    this.Id = id;
    this.Title = title;
    this.ParentId = parentid;
    Children = new List<CategorySelectItemListView>();
    }
    
    public CategorySelectItemListView(int id, string title, CategorySelectItemListView parent)
    {
    this.Id = id;
    this.Title = title;
    this.ParentId = parent.Id;
    Children = new List<CategorySelectItemListView>();
    }

     

    (3).视图Edit代码,注解部分的代码可以参考,我尝试用过,也可以达到目的,演练代码最好是用多种方式实现,查看其区别,这样掌握的牢固一些

    @{ ViewData["Title"] = "编辑文章"; }
    @model Article
    @section Scripts{
    <script type="text/javascript" src="~/js/jquery-3.6.1.min.js"></script>
    <script type="text/javascript">
    $(document).ready(function () {
    $.ajax({
    type: "GET",
    url: "/ArticleCategory/GetCategory",
    data: "{}",
    success: function (data) {
    console.log(data);
    var s = '<option value="0">请选择</option>';
    for (var i = 0; i < data.length; i++) {
    s += '<option value="' + data[i].Title + '"+>' + data[i].Id + '</option>';
    }
    $("#ArticleCategory").html(s);
    }
    });
    });
    </script>
    }
    
    <form action="/Article/Edit" method="post" enctype="multipart/form-data">
    @Html.AntiForgeryToken()
    <div>
    <label asp-for="Title">标题</label>
    <div>
    <input type="text" asp-for="Title" name="Title" placeholder="请输入标题">
    <input type="hidden" asp-for="Id" />
    </div>
    </div>
    <div>
    <label asp-for="CategoryId">文章类型</label>
    <div>
    @Html.DropDownList("ddl_CategoryId", ViewBag.database as IEnumerable<SelectListItem>)
    </div>
    </div>
    <div>
    <label>设置</label>
    <div>
    @*@Html.CheckBox("IsTop", Model.IsTop,new { value = Model.IsTop}) 置顶
    @Html.CheckBox("IsRed", Model.IsRed, new { value = Model.IsRed }) 热点
    @Html.CheckBox("IsSlide", Model.IsSlide, new { value = Model.IsSlide }) 幻灯*@
    <input asp-for="IsTop" />置顶
    <input asp-for="IsRed" />热点
    <input asp-for="IsSlide" />幻灯
    @*<input type="checkbox" name="IsTop" @(Html.Raw(@Model.IsTop ? "checked=\"checked\"" : "")) asp-for="IsTop" />置顶
    <input type="checkbox" name="IsRed" @(Html.Raw(@Model.IsRed ? "checked=\"checked\"" : "")) asp-for="IsRed" />热点
    <input type="checkbox" name="IsSlide" @(Html.Raw(@Model.IsSlide ? "checked=\"checked\"" : "")) asp-for="IsSlide" />幻灯*@
    @*<input type="checkbox" name="IsTop" asp-for="IsTop" />置顶
    <input type="checkbox" name="IsRed" asp-for="IsRed"/>热点
    <input type="checkbox" name="IsSlide" asp-for="IsSlide"/>幻灯*@
    </div>
    </div>
    <div>
    <label asp-for="ImageUrl">文章首页图</label>
    <div>
    <input type="file" asp-for="ImageUrl" name="ImageUrl" />
    <label asp-for="ImageUrl">@Model.ImageUrl</label>
    </div>
    </div>
    <div>
    <label asp-for="Content">内容</label>
    <div>
    <textarea placeholder="内容" asp-for="Content" name="Content" cols="30" rows="10"></textarea>
    </div>
    </div>
    <div>
    <label asp-for="Sort">排序</label>
    <div>
    <input type="text" placeholder="排序" asp-for="Sort" name="Sort" />
    </div>
    </div>
    <div>
    <label asp-for="ViewCount">点击量</label>
    <div>
    <input type="text" placeholder="点击量" asp-for="ViewCount" name="ViewCount" />
    </div>
    </div>
    <div>
    <label asp-for="IsPublish">是否发布</label>
    <div>
    <select asp-for="IsPublish" name="IsPublish" class="IsPublish">
    <option value="False"></option>
    <option value="True" selected></option>
    </select>
    </div>
    </div>
    <div>
    <label asp-for="Author">作者</label>
    <div>
    <input type="text" asp-for="Author" name="Author" placeholder="作者名">
    </div>
    </div>
    <div>
    <label asp-for="Source">来源</label>
    <div>
    <input type="text" asp-for="Source" name="Source" placeholder="文章来源">
    </div>
    </div>
    <div>
    <label asp-for="SeoTitle">SEO标题</label>
    <div>
    <input type="text" asp-for="SeoTitle" name="SeoTitle" placeholder="SEO标题">
    </div>
    </div>
    <div>
    <label asp-for="SeoKeyword">SEO关键词</label>
    <div>
    <input type="text" asp-for="SeoKeyword" name="SeoKeyword" placeholder="SEO关键词">
    </div>
    </div>
    <div>
    <label asp-for="SeoDescription">SEO摘要描述</label>
    <div>
    <input type="text" asp-for="SeoDescription" name="SeoDescription" placeholder="SEO摘要描述">
    </div>
    </div>
    <div>
    <div>
    <button type="submit">确定</button>
    <button type="reset">重置</button>
    </div>
    </div>
    </form>

     

    (4).视图Index列表的代码

    针对列表的显示,又专门编写了ArticeView的这个ViewModel。

    public class ArticleView
    {
    public int Id { get; set; }
    public int CategoryId { get; set; }
    public string CategoryName { get; set; }
    public string Title { get; set; }
    public int ViewCount { get; set; }
    public int Sort { get; set; }
    public string Author { get; set; }
    public string Source { get; set; }
    public int AddManagerId { get; set; }
    public DateTime AddTime { get; set; }
    }

     

    @using Humanizer;
    @using RjWebCms.Db;
    @using RjWebCms.Models.Articles;
    @model PaginatedList<ArticleView>
    @{
    ViewData["Title"] = "文章列表";
    }
    @section Scripts{
    <script src="~/js/jquery-2.1.0.min.js"></script>
    <script type="text/javascript">
    function DelAll() {
    var ids = document.getElementsByName("#chk_ids");
    var arrIds = "";
    var n = 0;
    for (var i = 0; i < ids.length; i++)
    {
    if (ids[i].checked == true) {
    arrIds += ids[i].value + ",";
    n++;
    }
    }
    if (n == 0) {
    alert("请选择要删除的信息");
    return;
    }
    arrIds = arrids.substr(0, arrIds.length - 1);
    //
    if (confirm("确定要全部删除选择信息吗")) {
    $.ajax({
    type: "post",
    url: "/Article/DeleteAll",
    data: { ids: arrIds },
    success: function (data, state) {
    alert('删除成功!');
    window.location.href = "";
    },
    
    error: function (data, state) {
    alert('删除失败');
    }
    });
    }
    }
    </script>
    }
    <div class="panel panel-default todo-panel">
    <div class="panel-heading">@ViewData["Title"]</div>
    @Html.AntiForgeryToken()
    <form asp-action="Index" method="get">
    <table>
    <tr><td><a asp-controller="Article" asp-action="Create">添加</a></td></tr>
    <tr>
    <td>查询关键词:<input type="text" name="SearchString" value="@ViewData["CurrentFilter"]" /></td>
    <td><input type="submit" value="查询" /></td>
    <td><a asp-action="Index">Back</a></td>
    <td><a asp-action="DeleteAll">批量删除</a></td>
    </tr>
    </table>
    </form>
    <table class="table table-hover">
    <thead>
    <tr>
    <td>&#x2714;</td>
    <td><a asp-action="Index" asp-route-sortOrder="@ViewData["NameSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">标题</a></td>
    <td>类别</td>
    <td><a asp-action="Index" asp-route-sortOrder="@ViewData["DateSortParm"]" asp-route-currentFilter="@ViewData["CurrentFilter"]">添加时间</a></td>
    <td>作者</td>
    <td>操作</td>
    </tr>
    @foreach (var item in Model)
    {
    <tr>
    <td><input type="checkbox" class="done-checkbox" name="chk_ids" value="@item.Id"></td>
    <td>@item.Title</td>
    <td>@item.CategoryName</td>
    <td>@item.AddTime</td>
    <td>@item.Author</td>
    <td>
    <a asp-action="Details" asp-route-id="@item.Id">Details</a>
    <a asp-action="Edit" asp-route-id="@item.Id">Edit</a>
    <a asp-action="Delete" asp-route-id="@item.Id">Delete</a>
    </td>
    </tr>
    }
    </thead>
    </table>
    @{
    var prevDisabled = !Model.HasPreviousPage ? "disabled" : "";
    var nextDisabled = !Model.HasNextPage ? "disabled" : ""; ;
    }
    
    <a asp-action="Index"
    asp-route-sortOrder="@ViewData["CurrentSort"]"
    asp-route-pageNumber="@(Model.PageIndex - 1)"
    asp-route-currentFilter="@ViewData["CurrentFilter"]"
    class="btn btn-default @prevDisabled">
    上一页
    </a>
    <a asp-action="Index"
    asp-route-sortOrder="@ViewData["CurrentSort"]"
    asp-route-pageNumber="@(Model.PageIndex + 1)"
    asp-route-currentFilter="@ViewData["CurrentFilter"]"
    class="btn btn-default @nextDisabled">
    下一页
    </a>
    <div class="panel-footer add-item-form">
    <!--TODO: Add item form -->
    </div>
    </div>

     

    (5).Controller部分的全部代码,注意看代码注释

    public class ArticleController : Controller
        {
            private readonly IHostEnvironment _hostEnvironment;
            private readonly IArticleService _articleService;
            private readonly IArticleCategoryService _articleCategoryService;
            private readonly AppDbContext _appDbContext;
            public ArticleController(IArticleService articleService, IArticleCategoryService articleCategoryService,AppDbContext appDbContext,IHostEnvironment hostEnvironment)
            {
                _hostEnvironment = hostEnvironment;
                _appDbContext = appDbContext;
                _articleService = articleService;
                _articleCategoryService = articleCategoryService;
            }
    
            public async Task<IActionResult> Index(string sortOrder, string currentFilter, string searchString, int? pageNumber)
            {
                ViewData["CurrentSort"] = sortOrder;
                ViewData["NameSortParm"] = String.IsNullOrEmpty(sortOrder) ? "name_desc" : "";
                ViewData["DateSortParm"] = sortOrder == "Date" ? "date_desc" : "Date";
    
                if (searchString != null)
                {
                    pageNumber = 1;
                }
                else
                {
                    searchString = currentFilter;
                }
                ViewData["CurrentFilter"] = searchString;
                var article = from s in _appDbContext.Article
                              join p in _appDbContext.ArticleCategory on s.CategoryId equals p.Id
                              select new ArticleView { 
                                Id = s.Id,
                                CategoryId = s.CategoryId,
                                CategoryName = p.Title,
                                Title = s.Title,
                                Sort = s.Sort,
                                AddManagerId = s.AddManagerId,
                                AddTime = s.AddTime,
                                Author = s.Author,
                                Source = s.Source,
                                ViewCount = s.ViewCount,
                              };
                if (!string.IsNullOrEmpty(searchString))
                {
                    article = article.Where(s => s.Title.Contains(searchString));
                }
                switch (sortOrder)
                {
                    case "name_desc":
                        article = article.OrderByDescending(s => s.Title) ;
                        break;
                    case "Date":
                        article = article.OrderBy(s => s.AddTime);
                        break;
                    case "date_desc":
                        article = article.OrderByDescending(s => s.AddTime);
                        break;
                    default:
                        article = article.OrderBy(s => s.Title);
                        break;
                }
                int pageSize = 4;
                return View(await PaginatedList<ArticleView>.CreateAsync(article.AsNoTracking(), pageNumber ?? 1, pageSize));
            }
    
    
            [HttpGet]
            public async Task<IActionResult> CreateAsync()
            {
                #region 绑定类别下拉框
                var categories = await _articleCategoryService.GetArticleCategory();//列出文章类别字典
                var categoryItems = new List<SelectListItem>()
                {
                    new SelectListItem(){ Value="0",Text="全部",Selected=true}
                };
                //全部列出并转成DropDownList对象
                List<CategorySelectItemListView> list = new List<CategorySelectItemListView>();
                foreach (var category in categories)
                {
                    list.Add(new CategorySelectItemListView { 
                        Id=category.Id,
                        Title = category.Title,
                        ParentId = category.ParentId
                    });
                }
    
                #region 循环嵌套调用
                //List<CategorySelectItemListView> list1 = GetChildCategory(list);
                //foreach (var li in list1)
                //{
                //    categoryItems.Add(new SelectListItem { Value = li.Id.ToString(), Text = li.Title });
                //    if (li.Children.Count > 0)
                //    { 
                //        foreach(var t in li.Children)
                //            categoryItems.Add(new SelectListItem { Value = t.Id.ToString(),Text= "|-" + t.Title });
                //    }
                //}
                #endregion
    
                #region  递归调用
                List<CategorySelectItemListView> list1 = GetChildCategory(list, new List<CategorySelectItemListView>(), 0);
                foreach (var li in list1)
                {
                    categoryItems.Add(new SelectListItem { Value = li.Id.ToString(), Text = li.Title });
                    if (li.Children.Count > 0)
                    {
                        foreach (var t in li.Children)
                            categoryItems.Add(new SelectListItem { Value = t.Id.ToString(), Text = "  |-" + t.Title });
                    }
                }
                #endregion
    
                ViewBag.database = categoryItems;
                #endregion
                return View();
            }
    
            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> CreateAsync(Article article,[FromForm]IFormCollection fromData)
            {
                //去掉对字段IsSystem的验证,IsSystem在数据库是bool类型,而前端是0和1,ModelState的验证总是报false,所以去掉对其验证
                //ModelState.Remove("IsSystem");//在View端已经解决了了bool类型,那么此行代码可以不用
                #region 下拉菜单
                string strCategoryId = Request.Form["ddl_CategoryId"];
                if (!string.IsNullOrEmpty(strCategoryId))
                    article.CategoryId = int.Parse(strCategoryId);
                else
                    article.CategoryId = 0;
                #endregion
    
                #region 复选框
                article.IsTop = fromData["IsTop"] != "false";//使用FormCollection时,可以这样
                article.IsRed = fromData["IsRed"] != "false";
                article.IsSlide = fromData["IsSlide"] != "false";
                //也可以这样取值,但要注意View内的写法
                //if (!string.IsNullOrEmpty(fromData["IsTop"]))
                //    article.IsTop = true;
                //else
                //    article.IsTop = false;
                #endregion
    
                #region 上传文件
                IFormFileCollection files = fromData.Files;
               foreach(var formFile in files)
                {
                    //var fileName = ContentDispositionHeaderValue.Parse(file.ContentDisposition).FileName.Trim('"');
                    string webContentPath = _hostEnvironment.ContentRootPath;
                    var fileExt = formFile.FileName.Substring(formFile.FileName.LastIndexOf('.'));//文件扩展名
                    var fileNew = DateTime.Now.ToString("yyyyMMddHHmmss") + fileExt; //给文件重新命名
                    
                    //string upLoadPath = webContentPath + $@"\{fileName}";
                    string upLoadPath = webContentPath + $@"\UpFiles";
                    var fileUrl = upLoadPath + $@"\{fileNew}";
    
                    if (formFile.Length > 0)
                    {
                        using (var stream = new FileStream(fileUrl,FileMode.Create))
                        {
                            await formFile.CopyToAsync(stream);
                        }
                    }
                    article.ImageUrl = "../UpFiles/" + fileNew;
    
    
                }       
                #endregion 
    
                if (ModelState.IsValid)
                {
                    var successful = await _articleService.AddArticleAysnc(article);
                    if (successful)
                        return RedirectToAction("Index");
                    else
                        return BadRequest("失败");
                }
                return View(article);
            }
    
    
            [HttpGet]
            public async Task<IActionResult> Edit(int id)
            {
    
                if (string.IsNullOrEmpty(id.ToString()))
                    return NotFound();
    
                var article = await _articleService.FindArticleAsync(id);
                if (article == null)
                    return NotFound();
    
                #region 绑定角色下拉框
                var categories = await _articleCategoryService.GetArticleCategory();//列出文章类别字典
                var categoryItems = new List<SelectListItem>()
                {
                    new SelectListItem(){ Value="0",Text="全部",Selected=true}
                };
                //全部列出并转成DropDownList对象
                List<CategorySelectItemListView> list = new List<CategorySelectItemListView>();
                foreach (var category in categories)
                {
                    list.Add(new CategorySelectItemListView
                    {
                        Id = category.Id,
                        Title = category.Title,
                        ParentId = category.ParentId
                    });
                }
                #region  递归调用
                List<CategorySelectItemListView> list1 = GetChildCategory(list, new List<CategorySelectItemListView>(), 0);
                foreach (var li in list1)
                {
                    categoryItems.Add(new SelectListItem { Value = li.Id.ToString(), Text = li.Title });
                    if (li.Children.Count > 0)
                    {
                        foreach (var t in li.Children)
                            categoryItems.Add(new SelectListItem { Value = t.Id.ToString(), Text = "  |-" + t.Title });
                    }
                }
                #endregion
    
                #region 遍历并选中
                foreach (SelectListItem item in categoryItems)
                {
                    if (item.Value == article.CategoryId.ToString())
                        item.Selected = true;
                }
                #endregion 
                ViewBag.database = categoryItems;
                #endregion
    
                return View(article);
            }
    
            [HttpPost]
            [ValidateAntiForgeryToken]
            public async Task<IActionResult> Edit(int id, [FromForm]Article article)
            {
                if (id != article.Id)
                {
                    return NotFound();
                }
                #region 下拉菜单
                string strCategoryId = Request.Form["ddl_CategoryId"];
                if (!string.IsNullOrEmpty(strCategoryId))
                    article.CategoryId = int.Parse(strCategoryId);
                else
                    article.CategoryId = 0;
                #endregion
                #region 复选框
                if (Request.Form["IsTop"].Contains("true"))
                    article.IsTop = true;
                else
                    article.IsTop = false;
                if (Request.Form["IsRed"].Contains("true"))
                    article.IsRed = true;
                else
                    article.IsRed = false;
                if (Request.Form["IsSlide"].Contains("true"))
                    article.IsSlide = true;
                else
                    article.IsSlide = false;
                #endregion 
                //ModelState.Remove("IsTop");
                //ModelState.Remove("IsRed");
                //ModelState.Remove("IsSlide");
                if (ModelState.IsValid)
                {
                    try
                    {
                        var result = await _articleService.UpdateArticleAsync(id, article);
                        //跳转
                        if (result)
                            return RedirectToAction("Index");
                        else
                            return BadRequest("编辑失败");
                    }
                    catch (Exception ex)
                    {
                        return BadRequest("编辑失败");
                    }
                }
                else
                {
                    return BadRequest("数据输入有误!");
                }
            }
    
            /// <summary>
            /// 递归函数,实现获取子菜单
            /// </summary>
            /// <param name="lists">递归前的列表</param>
            /// <param name="newlists">递归后的新列表</param>
            /// <param name="parentId">父Id</param>
            /// <returns></returns>
            public static List<CategorySelectItemListView> GetChildCategory(List<CategorySelectItemListView> lists, List<CategorySelectItemListView> newlists, int parentId)
            {
                newlists = new List<CategorySelectItemListView>();
                List<CategorySelectItemListView> tempList = lists.Where(c => c.ParentId == parentId).ToList();
                for (int i = 0; i < tempList.Count; i++)
                {
                    CategorySelectItemListView category = new CategorySelectItemListView();
                    category.Id = tempList[i].Id;
                    category.ParentId = tempList[i].ParentId;
                    category.Title = tempList[i].Title;
                    category.Children = GetChildCategory(lists, newlists, category.Id);
                    newlists.Add(category);
                }
                return newlists;
            }
    
            /// <summary>
            /// 循环嵌套,实现获取子菜单
            /// </summary>
            /// <param name="lists">循环遍历前的列表</param>
            /// <returns></returns>
            public static List<CategorySelectItemListView> GetChildCategory(List<CategorySelectItemListView> lists)
            {
                List<CategorySelectItemListView> categorylist = new List<CategorySelectItemListView>();
                for (int i = 0; i < lists.Count; i++)
                {
                    if (0 == lists[i].ParentId)
                        categorylist.Add(lists[i]);
    
                    for (int j = 0; j < lists.Count; j++)
                    {
                        if (lists[j].ParentId == lists[i].Id)
                            lists[i].Children.Add(lists[j]);
                    }
                }
                return categorylist;
            }
    
    
        }

     

    (6).Service应用层代码

     

        public class ArticleService : IArticleService
        {
            private readonly AppDbContext _appDbContext;
            public ArticleService(AppDbContext appDbContext)
            {
                _appDbContext = appDbContext;
            }
            /// <summary>
            /// 添加文章
            /// </summary>
            /// <param name="article"></param>
            /// <returns></returns>
            public async Task<bool> AddArticleAysnc(Article article)
            {
                article.IsDeleted = false;
                article.AddManagerId = 1;//用户id
                article.AddTime = DateTime.Now;
                article.IsPublish = true;
                await _appDbContext.Article.AddAsync(article);
                var result = await _appDbContext.SaveChangesAsync();
                return result == 1;
            }
    
            /// <summary>
            /// 删除文章
            /// </summary>
            /// <param name="Id"></param>
            /// <returns></returns>
            public async Task<bool> DeleteArticleAsync(int Id)
            {
                var article = await _appDbContext.Article.FirstOrDefaultAsync(x => x.Id == Id);
                if (article != null)
                {
                    _appDbContext.Article.Remove(article);
                }
                var result = await _appDbContext.SaveChangesAsync();
                return result == 1; //注意(result==1 如果等式成立,则返回true,说明删除成功)
            }
    
            /// <summary>
            /// 按Id查询文章
            /// </summary>
            /// <param name="Id"></param>
            /// <returns></returns>
            public async Task<Article> FindArticleAsync(int Id)
            {
                var item = await _appDbContext.Article.Where(x => x.Id == Id).FirstOrDefaultAsync();
                return item;
            }
    
            /// <summary>
            /// 按标题查询文章
            /// </summary>
            /// <param name="title"></param>
            /// <returns></returns>
            public async Task<Article[]> GetArtcleByTitle(string title)
            {
                var items = await _appDbContext.Article.Where(x => x.Title.Contains(title)).ToArrayAsync();
                return items;
            }
    
            /// <summary>
            /// 查询文章
            /// </summary>
            /// <returns></returns>
            public async Task<Article[]> GetArticles()
            {
                var items = await _appDbContext.Article.Where(x => x.IsDeleted==false).ToArrayAsync();
                return items;
            }
    
            /// <summary>
            /// 更新文章
            /// </summary>
            /// <param name="id"></param>
            /// <param name="article"></param>
            /// <returns></returns>
            public async Task<bool> UpdateArticleAsync(int id, Article article)
            {
                var oldArticle = await  FindArticleAsync(id); //找出旧对象
    
                //将新值赋到旧对象上
                oldArticle.Title = article.Title;
                oldArticle.CategoryId = article.CategoryId;
                oldArticle.SeoDescription = article.SeoDescription;
                oldArticle.SeoTitle = article.SeoTitle;
                oldArticle.SeoKeyword = article.SeoKeyword;
                oldArticle.Content = article.Content;
                oldArticle.Sort = article.Sort;
                oldArticle.Source = article.Source;
                oldArticle.IsSlide = article.IsSlide;
                oldArticle.IsPublish = article.IsPublish;
                oldArticle.IsRed = article.IsRed;
                oldArticle.IsTop = article.IsTop;
                oldArticle.ViewCount = article.ViewCount;
                oldArticle.Author = article.Author;
                oldArticle.ImageUrl = article.ImageUrl;
    
                oldArticle.ModifyManagerId = 11;//
                oldArticle.ModifyTime = DateTime.Parse(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
    
                //对旧对象执行更新
                _appDbContext.Entry(oldArticle).State = EntityState.Modified;
                var result = await _appDbContext.SaveChangesAsync();
                return result == 1;
            }
        }

     

     

    再谈CheckBox的使用

    1.在View视图页增加的代码格式如果为:

    <input type="checkbox" name="IsTop" asp-for="IsTop" />置顶

    或者是这样:

    <input asp-for="IsTop" />置顶

    那么在生成的html代码中,都会自动成id,name,type=“checkbox” value的属性。

    2.在Controller中进行取值时的代码为:

    if (Request.Form["IsTop"].Contains("true"))

    article.IsTop = true;

    else

    article.IsTop = false;

    跟踪时发现,View中Checkbox选中是,会产生true和false两个值,如图跟踪变量发现:

    如此,取值时,就用了Contains功能,因为View中CheckBox没选中,这只有一个false值;

    3.在View视图页增加代码的格式如果为:

    <input type="checkbox" name="IsTop" @(Html.Raw(@Model.IsTop ? "checked=\"checked\"" : "")) asp-for="IsTop" />置顶

    4.在Controller中进行取值时的代码为:

    if (!string.IsNullOrEmpty(Request.Form["IsTop"]))

    article.IsTop = true;

    else

    article.IsTop = false;

    跟踪时发现,View中的CheckBox选中是,取到的值为“on”,如图跟踪发现:

    所以,才用了IsNullOrEmpty这个函数,依据判空来确定是否选中。

    但是这样写有个问题,在ModelState.IsValid()的模型验证中,一直无法通过,IsTop一直为false,为此,我干脆就把其去除掉验证:

    ModelState.Remove("IsTop");//去除name=IsTop的checkbox的模型验证

    5.使用Checkbox,还是要看给在数据表中为其定义的字段类型,Model中的指定类型和验证属性,如果你赋予了Value值,那么就在Controller中取值,Asp.Net Core中Checkbox默认是True和False的值,网上关于@Html.CheckBox()形式也行,你可以尝试跟踪变量值来判断如何处理,其宗旨就是根据具体条件来处理。

    本帖子中包含资源

    您需要 登录 才可以下载,没有帐号?立即注册