ASP.NET MVC3中另一种无限级分类方法:扩展HtmlHelper

在Web开发中,无限级的分类的应用很多,我们能够用各种方法来实现无限级分类。比如,jQuery中的treeTable Plugin可以实现无限级分类,当然,jQuery总归是客户端的,还需要服务端配合生成Table。在ASP.NET 中有SiteMap,可以实现生成无限级分类。即使是在ASP.NET MVC中,也有开源的ASP.NET MVC SiteMap Provider。

然而,jQuery中的treeTable是以生成表格的形式生成,没有办法处理li格式;ASP.NET 原有的SiteMap在MVC中表现不佳,毕竟机制上存在出入;开源的ASP.NET MVC SiteMap Provider倒是一个选择,只是,个人看到繁杂的配置,顿时失去了耐心。因此,自己在HtmlHelper上进行了扩展,使得在视图中也可以正常使用无限级分类,具体代码如下:

     public interface IMutilevelMenuable
    {
        int Id {get;}
        string Name { get; }
        string AliasName { get; }
        int Parent { get; }
    }

首先定义一个接口,当然,如果你是一个类,那也就不是必须的了。

    public static class MutiLevelMenuHelper
    {
        /// <summary>
        /// 生成无限级的分类列表
        /// </summary>
        /// <param name="helper">HtmlHelper扩展方法对象</param>
        /// <param name="menus">所有的对象</param>
        /// <param name="menuId">要查找子分类的父分类ID</param>
        /// <param name="currentId">当前页面的分类ID</param>
        /// <param name="currentMenuUrlParameter">在URL中使用的分类ID的参数名称</param>
        /// <returns>返回无限级分类的HTML</returns>
        public static MvcHtmlString MutiLevelMenu<T>(this HtmlHelper helper, IEnumerable<T> menus, int menuId, int currentId, string currentMenuUrlParameter) where T : IMutilevelMenuable
        {
            IEnumerable<T> innerMenus = menus.Where(i => i.Parent == menuId);
            if (innerMenus.Count() == 0) return MvcHtmlString.Create("");
            System.Web.Routing.RouteData rd = helper.ViewContext.RouteData;
            string controller = rd.GetRequiredString("controller");
            string action = rd.GetRequiredString("action");

            System.Web.Routing.RouteValueDictionary values =rd.Values;
            if(!values.ContainsKey(currentMenuUrlParameter))
                values[currentMenuUrlParameter] = currentId;
            #region Code by Mitchell @2012-06-08
            
            StringBuilder menuHtml = innerMenus.Aggregate(new StringBuilder().AppendFormat("<ul class=\"node-for-node{0}\">\r\n", menuId), (seed, menu) =>
            {
                values[currentMenuUrlParameter] = menu.Id;
                if (menu.Id == currentId)
                {
                    seed
                        .AppendFormat("<li id=\"node{0}\">\r\n", menu.Id)
                        .AppendFormat("<h3>{0}</h3>", menu.Name)
                        .Append(MutiLevelMenu(helper, menus, menu.Id, currentId, currentMenuUrlParameter))
                        .Append("</li>\r\n");
                }
                else
                {
                    seed
                        .AppendFormat("<li id=\"node{0}\">\r\n", menu.Id)
                        .Append(helper.ActionLink(menu.Name, action, controller, values, new Dictionary<string, object> { { "class", "menu-link" } }).ToHtmlString())
                        .Append(MutiLevelMenu(helper, menus, menu.Id, currentId, currentMenuUrlParameter))
                        .Append("</li>\r\n");
                }
                return seed;
            });
            menuHtml.Append("</ul>");
            #endregion
            return MvcHtmlString.Create(menuHtml.ToString());
        }
    }
}

之后定义一个HtmlHelper的泛型方法,改方法参数T必须实现了前面定义的接口,这样在方法体内就可以实现调用。

至于方法体里面,就是个递归,没有什么稀奇的东西。

由于是扩展方法,所以必须引用:

using System.Web.Mvc;
using System.Web.Mvc.Html;

之后,在视图中使用@using 引用本扩展方法即可。

在需要产生无限级分类的地方使用下面代码:

@Html.MutiLevelMenu(Model.AllCategories, 0, 1, "Id")

参数的说明见方法定义。

这样就可以了。

至于样式,根据个人喜好定义即可。

 

 

Friday, June 08, 2012 | .NET技术

文章评论

No comments posted yet.

发表评论

Please add 8 and 6 and type the answer here:

关于博主

  一枚成分复杂的网络IT分子,属于互联网行业分类中的杂牌军。