【问题标题】:Integrate a general menu in my asp.net mvc solution在我的 asp.net mvc 解决方案中集成一个通用菜单
【发布时间】:2011-04-14 10:50:43
【问题描述】:

为了我的学习,我正在使用 ASP.NET MVC3 构建一个文档管理解决方案。以下是我管理的页面:

  • 搜索/结果页面(项目列表)
  • 收藏页面(项目列表)
  • 编辑页面
  • 创建页面

我还有一个 Site.Master 页面,我在屏幕左侧显示了一个树形视图菜单。因此,无论用户位于网站中的哪个位置,树形视图菜单都会通过在菜单中强调他的位置来显示他的位置。

为了构建树形视图菜单,我使用下面的代码(为了便于阅读而进行了清理):

        <ul id="treemenu1" class="treeview">                                    
                <li>Documents
                    <ul>  
                        <%= Html.TreeviewMenu(TreeMenu.Create("Search", "Search", "Affaires", null))%>
                        <%= Html.TreeviewMenu(TreeMenu.Create("Favorite", "Favorite", "Affaires", null))%>
                        <%= Html.TreeviewMenu(TreeMenu.Create("New", "Create", "Affaires", null))%>
                   </ul>  
                </li>
        </ul>

问题是我需要在我的菜单中为活动项目加下划线。因此,如果用户正在显示搜索页面,我的搜索菜单条目必须加下划线。我该如何进行?我正在考虑将此信息集成到传递给每个视图页面的强类型视图模型中,但它失败了,因为每个页面都使用不同的视图模型。我不喜欢使用会话变量,因为它不是一个干净的解决方案。

有什么想法吗?

带有会话变量的解决方案:我将“当前菜单项”保存在会话变量中(来自我的控制器)。因此,每当重新加载 Site.Master 页面时,它都会重新创建每个树形视图菜单项。对于每一项,它都会检查项目是否等于会话变量。如果是,则将“selected”类添加到项目中(css 以蓝色突出显示)。

我不太喜欢使用会话变量。也许还有更优雅的解决方案?

【问题讨论】:

    标签: asp.net asp.net-mvc-3


    【解决方案1】:

    如何使用助手:

    public static MvcHtmlString MenuItem(
        this HtmlHelper htmlHelper, 
        string text,
        string action, 
        string controller
    )
    {
        var li = new TagBuilder("li");
        var routeData = htmlHelper.ViewContext.RouteData;
        var currentAction = routeData.GetRequiredString("action");
        var currentController = routeData.GetRequiredString("controller");
        if (string.Equals(currentAction, action, StringComparison.OrdinalIgnoreCase) &&
            string.Equals(currentController, controller, StringComparison.OrdinalIgnoreCase))
        {
            li.AddCssClass("active");
        }
        li.InnerHtml = htmlHelper.ActionLink(text, action, controller).ToHtmlString();
        return MvcHtmlString.Create(li.ToString());
    }
    

    然后:

    <ul>
        <%= Html.MenuItem("Search", "Search", "Affaires") %>
        <%= Html.MenuItem("Favorite", "Favorite", "Affaires") %>
        <%= Html.MenuItem("New", "Create", "Affaires") %>
    </ul>
    

    如果您导航到/Affaires/Favorite,可能会产生以下结果:

    <ul>
        <li><a href="/Affaires/Search">Search</a></li>
        <li class="active"><a href="/Affaires/Favorite">Favorite</a></li>
        <li><a href="/Affaires/Create">New</a></li>
    </ul>
    

    【讨论】:

    • 是的,这可能是最合乎逻辑的事情。不敢相信我没有想到这一点。
    • @Darin:您的解决方案是最有效的。这就是我一开始使用的解决方案。直到我在页面中使用表单来管理搜索页面结果表中的已检查项目。如果表单在我的控制器中提交并受到威胁(将我的表单发布到名为 ManageCheckedItems 的操作),接下来我们将返回相同的视图页面。然后重新加载 Site.Master 页面并执行 html 帮助程序(如您的)。 这里的问题是这里的 routeData.GetRequiredString("action") 等于 ManageCheckedItems 而不是 Search!
    • 这是我对这个解决方案的大问题。总结一下:如果我使用的表单的发布操作与初始操作页面不同,我在返回重新加载页面时会遇到问题。我不知道我是否清楚。
    • @Bronzato,你很清楚。我明白这个问题。持久化在 POST 期间丢失的调用操作是一个问题。一种可能的解决方法是将原始操作和控制器包含在 POST 请求中(可能在具有一些预定义名称的隐藏字段中)。然后在帮助程序中,您可以检查 HTTP 动词,如果是 POST,请查看这些值的 POST 数据,如果您确定它们的存在,则使用它们进行比较,而不是从 RouteData 获取一次。
    • @Darin:这让我很烦......我担心这个最初很好的解决方案会变成一个复杂的解决方案......也许另一个“更清洁”的解决方案是可能的?
    【解决方案2】:

    好吧,有一个简单有效的解决方案:让每个页面都发出信号是否是活动页面,并使用 jQuery 设置一个 css 类。

    假设您呈现的 html 看起来像:

    <ul id="treemenu1" class="treeview">                                    
        <li>Documents
            <ul>
                <li class="search"></li>
                <li class="favorite"></li>
            </ul>
        </li>
    </ul>
    

    在每个页面的底部,执行类似的操作(这将位于搜索视图上):

    <script type="text/javascript">
        $(document).ready(function () {
            // Set active nav
            $('#treemenu1 li.search').addClass('selected');
        });
    </script>
    

    根据新信息更新

    使用控制器中的ViewBag 属性可能比会话变量更简洁。

    public ActionResult Search(/*whatever*/)
    {
        // do things
    
        // set the selevted view
        ViewBag.SelectedMenuItem = "search";
    
        return View();
    }
    

    然后在您的母版页中,您可以检查 &lt;%: ViewBag.SelectedMenuItem %&gt;

    请注意,SelectedMenuItem 是一个随机名称。 The ViewBag property is of type dynamic 所以你可以使用任何你喜欢的属性名称。

    【讨论】:

    • 这可能是一个解决方案,但我有用于多种目的(搜索、收藏、...)的相同视图页,所以在这种情况下我遇到了问题。否则,您的解决方案有效。我会考虑一下。也许还有其他选择?还是谢谢。
    • @Bronzato - “同一视图页面用于多种用途”到底是什么意思?
    • 我的意思是我有一个名为 Search.aspx 的页面,用于搜索和收藏菜单选项。我在我的问题中添加了更多信息(见上文)。
    猜你喜欢
    • 2011-05-01
    • 2015-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多