C# ASP.Net MVC3 Razor中的动态菜单

5

说明

我正在尝试创建一个动态菜单,从数据库加载项目。 我需要菜单内最多有三个级别,像这样:

<ul>
   <li>Home</li>
   <li>Peoples
      <ul>
         <li>Employee
            <ul>
              <li>Create</li>
              <li>List</li>
              <li>Edit</li>
            </ul>
         </li>
         <li>Training</li>
         <li>Material Requisition</li>
      </ul>
   </li>
</ul

现在,这就是我今天的情况,但没有成功:

部分视图“TopBar.cshtml”在每个页面中显示,并且像这样在“_Layout.cshtml”中调用:

_Layout.cshtml

<body>
    @Html.Partial("TopBar")
    <div class="container body-content">
        @RenderBody()
        (...)

而“TopBar.cshtml”使用以下代码显示数据:

@model IEnumerable<SIGO.Models.TopMenu>
<div class="navbar navbar-inverse navbar-fixed-top">
    <div class="container">
        <div class="navbar-header">
            <div class="SigoLogo" onclick="location.href='@Url.Action("")'">
                <a href="@Url.Action("Index", "Home")" title="Início">
                    <img src="~/Content/images/Wlogo.png" />
                </a>
            </div>
            <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"></button>
        </div>
        <div class="navbar-collapse collapse">
            <ul class="nav navbar-nav">
                @if (Model != null){
                    foreach(var item in Model.Where(p => p.Nivel == 0)) {
                        if (Model.Where(s1 => s1.Parent == item.TopMenuID) != null) {
                            <li>@item.Descricao
                                <ul>
                                    @foreach (var sub1 in Model.Where(s1 => s1.Parent == item.TopMenuID)) {
                                        if (Model.Where(s2 => s2.Parent == sub1.TopMenuID) != null) {
                                            <li>@sub1.Descricao
                                                <ul>
                                                    @foreach (var sub2 in Model.Where(s2 => s2.Parent == sub1.TopMenuID)) {
                                                    <li>@Html.ActionLink(sub2.Descricao,sub2.Action,sub2.Controller)</li>
                                                    }
                                                </ul>
                                            </li>
                                        }else{
                                            <li>@Html.ActionLink(sub1.Descricao,sub1.Action,sub1.Controller)</li>
                                        }
                                    }
                                </ul>
                            </li>
                        }else{
                            <li>@Html.ActionLink(item.Descricao,item.Action,item.Controller)</li>
                        }
                    }
                }
            </ul>
        </div>
    </div>
</div>

这是“TopMenu”类。
    public class TopMenuItem {
            [Key]
            [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
            public int Id { getset; }             //Iterator
            public int Parent { getset; }         //TopMenuItem parent id
            public bool Group { getset; }         //If this have another item below
            public string Descricao { getset; }   //Text to show
            public string Action { getset; }      //Action to Go
            public string Controller { get; set; }  //Controller to Go
    }

所有这些都导致了空白列表,就像一个干净的数据库。 但是,当我调用一个名为List的操作时,会出现冲突,因为视图“ List.cshtml”和“ TopBar.cshtml”都以以下方式开头:
@model IEnumerable<SIGO.Models.Employee>

或者

@model IEnumerable<SIGO.Models.TopMenu>

P.S.: 我没有使用任何控制器来处理TopMenu中的数据。

问题

  • 我应该如何实现这个TopMenu?
  • 你有其他的解决方案吗?

谢谢!对于翻译中的任何错误表示抱歉。

4个回答

6

这是通过上面的答案得出的解决方案

感谢大家的帮助

类:TopMenu.cs

    public class TopMenu {
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public int Id { getset; }             //Iterator
        public int Parent { getset; }         //TopMenuItem parent id
        public bool Group { getset; }         //If this have another item below
        public string Descricao { getset; }   //Text to show
        public string Action { getset; }      //Action to Go
        public string Controller { get; set; }  //Controller to Go
    }

上下文:SigoContext.cs

    public class SigoContext : DbContext {
        public SigoContext() : base("SigoMain") {}
            public DbSet<TopMenu> TopMenu{ get; set; }
        }
    }

控制器:SigoController.cs

    public class SystemController : Controller {
        private SigoContext db = new SigoContext();

        [ChildActionOnly]
        public ActionResult TopMenu() {
            return PartialView("TopBar",db.TopMenu);
        }
    }

Layout: _Layout.cshtml

...
<body>
    @{Html.RenderAction("TopMenu", "System");}
    <div class="container body-content">
        @RenderBody()
...

局部视图:TopMenu.cshtml

@model IEnumerable<SIGO.Models.TopMenu>
    <div class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
            <div class="navbar-header">
                <div class="SigoLogo">
                    <a href="@Url.Action("Index", "Home")" title="Início">
                        <img src="~/Content/images/Wlogo.png" />
                    </a>
                </div>
                <button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse"></button>
            </div>
            <div class="navbar-collapse collapse">
                <ul class="nav navbar-nav">
                    @if (Model != null){
                        foreach(var item in Model.Where(p => p.Parent == 0)) {
                            if (Model.Where(s1 => s1.Parent == item.Id) != null) {
                                <li>@item.Descricao
                                    <ul>
                                        @foreach (var sub1 in Model.Where(s1 => s1.Parent == item.Id)) {
                                            if (Model.Where(s2 => s2.Parent == sub1.Id) != null) {
                                                <li>@sub1.Descricao
                                                    <ul>
                                                        @foreach (var sub2 in Model.Where(s2 => s2.Parent == sub1.Id)) {
                                                        <li>@Html.ActionLink(sub2.Descricao,sub2.Action,sub2.Controller)</li>
                                                        }
                                                    </ul>
                                                </li>
                                            }else{
                                                <li>@Html.ActionLink(sub1.Descricao,sub1.Action,sub1.Controller)</li>
                                            }
                                        }
                                    </ul>
                                </li>
                            }else{
                                <li>@Html.ActionLink(item.Descricao,item.Action,item.Controller)</li>
                            }
                        }
                    }
                </ul>
            </div>
        </div>
    </div>

感谢大家!

1
你需要将模型传递到部分视图中。相反,这个条件将始终为false,什么也不会被渲染:
@if (Model != null)

所以,您需要像这样呈现视图:

@Html.Partial("TopBar", model)

在您的情况下,由于此代码位于布局视图中,因此无法获取模型。唯一合理的实现方法是创建一个控制器来提供模型。如果这样做,您应该使用ActionRenderAction(请参见 MSDN文档)。即像这样实现:
- 创建一个名为MenuController的控制器,并创建一个名为Menu的动作,返回一个PartialView,用于呈现菜单。在此操作内部创建模型,并使用return Partial("Menu",model),其中"Menu"指向一个"Menu.cshtml"视图,而模型具有呈现此视图所需的数据。此操作将呈现菜单。 - 使用Html.RenderAction("Menu","Menu")在布局内呈现菜单。第一个"Menu"参数是动作名称,第二个是控制器名称。

谢谢!创建MenuController并在“_Layout.cshtml”中调用TopMenu操作解决了我的问题。 - Anpix

1
创建一个单独的控制器/动作方法来构建您的菜单,并使用@Html.Action()调用它。例如:
public class MenuController : Controller
{
  [ChildActionOnly]
  public ActionResult Index()
  {
    // Build your menu model;
    return PartialView(model);
  }
}

然后在您的布局中。
@Html.Action("Index", "Menu")

谢谢!只差一个细节: 1)在布局中,我使用了“@{Html.RenderAction(“TopMenu”,“System”);}”并且可以工作。 2)在控制器内,我在操作外部使用了“private SigoContext db = new SigoContext();”,在操作内部使用了“return PartialView(“TopBar”,db.TopMenu);”。 - Anpix
点1):它们都基本上做同样的事情。不同之处在于@Html.RenderAction()直接将结果呈现给响应(如果操作返回大量HTML,则更有效),而@Html.Action()返回一个带有结果的字符串。点2):我不明白你在问什么 - 有问题吗? - user3559349
这不是问题。我只是说一下在你的帮助下我是如何得出解决方案的。 - Anpix

1
你可以尝试这样做。 我正在使用这个方法,它有效。 查看代码。
<ul id="nav">
        @foreach (var p in Model.Where(a => a.MENU_MASTER.PARENT_ID == 0))
        {

            if (Model.Where(a => a.MENU_MASTER.PARENT_ID == p.MENU_MASTER.OBJECT_ID).Any())
            {
            <li class="has-sub"><a href="#">@p.MENU_MASTER.OBJECT_NAME</a>
                <ul>
                    @foreach (var c in Model.Where(g => (g.MENU_MASTER.PARENT_ID == p.MENU_MASTER.OBJECT_ID)))
                    {
                        if (Model.Where(a => a.MENU_MASTER.PARENT_ID == c.MENU_MASTER.OBJECT_ID).Any())
                        {
                        <li class="has-sub"><a href="#"><span>@c.MENU_MASTER.OBJECT_NAME</span></a>
                            <ul>
                                @foreach (var d in Model.Where(a => a.MENU_MASTER.PARENT_ID == c.MENU_MASTER.OBJECT_ID))
                                {
                                    <li><a  href="@Url.Action(@d.MENU_MASTER.ACTION_NAME, @d.MENU_MASTER.CONTROLLER_NAME)">
                                        <span>@d.MENU_MASTER.OBJECT_NAME</span></a> </li>
                                }
                            </ul>
                        </li>

                        }
                        else
                        {
                        <li><a  href="@Url.Action(@c.MENU_MASTER.ACTION_NAME, @c.MENU_MASTER.CONTROLLER_NAME)">
                            <span>@c.MENU_MASTER.OBJECT_NAME</span></a> </li>  
                        }

                    }
                </ul>
            </li>
            }
            else
            {
            <li><a class="hsubs" href="#">@p.MENU_MASTER.OBJECT_NAME</a></li>
            }

        }
    </ul>

控制器代码
 public ActionResult menu()
        {
            List<PartialClass> Q = new List<PartialClass>();
            var query = ctx.MENU_MASTER.Select(a => new { a.ACTION_NAME, a.CONTROLLER_NAME, a.OBJECT_ID, a.OBJECT_NAME, a.PARENT_ID });
            foreach (var item in query)
            {
                PartialClass cs = new PartialClass();
                cs.MENU_MASTER.ACTION_NAME = item.ACTION_NAME;
                cs.MENU_MASTER.CONTROLLER_NAME = item.CONTROLLER_NAME;
                cs.MENU_MASTER.OBJECT_ID = item.OBJECT_ID;
                cs.MENU_MASTER.OBJECT_NAME = item.OBJECT_NAME;
                cs.MENU_MASTER.PARENT_ID = item.PARENT_ID;
                Q.Add(cs);
            }

            return View(Q);
        }

模型类
public class MENU_MASTER
    {
        [Key]
        public decimal OBJECT_ID { get; set; }
        public string OBJECT_NAME { get; set; }
        public Nullable<decimal> OBJECT_TYPE { get; set; }
        [ForeignKey("MENU_GROUP")]
        public Nullable<decimal> GROUP_ID { get; set; }
        public string LINK_NAME { get; set; }
        public string IMAGE_PATH { get; set; }
        public Nullable<decimal> ORDER_OF_APEARANCE { get; set; }
        public Nullable<decimal> CREATED_BY { get; set; }
        public Nullable<System.DateTime> CREATED_ON { get; set; }
        public Nullable<decimal> MODIFIED_BY { get; set; }
        public Nullable<System.DateTime> MODIFIED_ON { get; set; }
        public string CONTROLLER_NAME { get; set; }
        public string ACTION_NAME { get; set; }
        [ForeignKey("MODULE_MASTER")]
        public Nullable<decimal> MODULE_ID { get; set; }
        public string DESCRIPTION { get; set; }
        public Nullable<decimal> PARENT_ID { get; set; }

        public virtual MENU_GROUP MENU_GROUP { get; set; }
        public virtual MODULE_MASTER MODULE_MASTER { get; set; }
    }

感谢您的回答,@Pawan!您帮助了我解决另一个问题。 - Anpix

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接