将引导选项卡设置为活动状态

时间:2017-08-29 22:45:07

标签: c# asp.net asp.net-mvc

我在bootstrap中有一些标签,必须根据被击中的动作设置为活动状态。我也有子标签,必须根据被击中的动作设置为活动状态。

以下是它的外观图像:

因此,当子选项卡处于活动状态时,父选项卡也必须处于活动状态。

enter image description here

所以我想创建一个新的Attribute,我为每个动作保存一个pageId,根据视图中的pageId,我可以将它设置为活动状态:

这是属性:

public class YcoPageId : Attribute
{
    public YcoPageId(int pageId)
    {
        PageId = pageId;
    }
    public int PageId { get; } 
} 

以下是行动:

[YcoPageId(1)]
public ActionResult Admin()
{
    return View();
}

对于视图,我想创建一个扩展方法,以查看选项卡和子选项卡是否有效!

这是我的代码:

public static bool IsActive(this HtmlHelper htmlHelper, params int[] ids)
{
    var viewContext = htmlHelper.ViewContext;
    var action = viewContext....
    //How to get the YcoPageId attribute from here and see the Id
    //Here i will test if ids contain id but dont know how to get it...
}

如果您认为为每个页面添加一个ID是个坏主意,我认为我会将此ID用于其他目的,因为它将像特定操作的标识符...

所以我的问题是如何在我的扩展方法中获取当前操作的属性YcoPageId

视图将如下所示:

<li class="@(Html.IsActive(1, 4, 5... etc)? "active" : "")">
    <a href="@url">
        <div class="row text-center">
            <div class="col-md-12">
                <i class="fa @fontAwesomeIcon fa-4x" aria-hidden="true"></i>
                <br/>@menuName
            </div>
        </div>
    </a>
</li>

如果有更好的想法如何解决这个问题,请继续!

2 个答案:

答案 0 :(得分:1)

以下是我对此问题的解决方案:

首先创建了一个actionfilter属性,如下所示:

public class YcoPageIdAttribute : ActionFilterAttribute
{
    public YcoPageIdAttribute(int pageId)
    {
        PageId = pageId;
    }
    public int PageId { get; }
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Result is ViewResult)
        {
            filterContext.Controller.TempData[DomainKeys.ViewPageId] = PageId;
        }
        else 
        {
            throw new Exception("Only ViewResult has unique id");
        } 
        base.OnActionExecuted(filterContext);
    }
} 

然后我的行动看起来像这样:

[YcoPageId(1)]
public ActionResult Admin()
{ 
    return View();
}

我创建了一个扩展方法,如下所示:

public static bool IsActive(this HtmlHelper htmlHelper, params int[] ids)
{
    var viewContext = htmlHelper.ViewContext;
    return viewContext.TempData.ContainsKey(DomainKeys.ViewPageId) && 
        int.Parse(viewContext.TempData.Peek(DomainKeys.ViewPageId).ToString()).In(ids);
}

由于我现在知道动作的id,所以我只需要在视图中输入如下代码:

<li class="@(Html.IsActive(1)? "active" : "")">
    <a href="@url">
        <div class="row text-center">
            <div class="col-md-12">
                <i class="fa @fontAwesomeIcon" aria-hidden="true"></i>
                <br /><small>@menuName</small>
            </div>
        </div>
    </a>
</li>

我在启动时创建了另一种方法来检查我是否有重复值的操作,如下所示:

public static void CheckForDuplicateActionId()
{
    Assembly asm = Assembly.GetExecutingAssembly();
    var controllerActionlist = asm.GetTypes()
        .Where(type => typeof(Controller).IsAssignableFrom(type))
        .SelectMany(type => type.GetMethods(BindingFlags.Instance | BindingFlags.DeclaredOnly |
                                            BindingFlags.Public))
        .Where(m => !m.GetCustomAttributes(typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute),
            true).Any())
        .Where(m => m.GetCustomAttribute<YcoPageIdAttribute>() != null)
        .Select(
            x =>
                new
                {
                    Controller = x.DeclaringType.Name,
                    Area = x.DeclaringType.FullName,
                    Action = x.Name,
                    ReturnType = x.ReturnType.Name,
                    Id = x.GetCustomAttribute<YcoPageIdAttribute>().PageId
                })
        .ToList();
    var actionIds = controllerActionlist.Select(x => x.Id).ToList();
    var actionIdsGrouped = actionIds.GroupBy(x => x).Where(x => x.Count() > 1).ToList();
    if (!actionIdsGrouped.IsNullOrEmpty()) 
    {
        StringBuilder error = new StringBuilder("");
        actionIdsGrouped.ForEach(actionId =>
        {
            var actions = controllerActionlist.Where(x => x.Id == actionId.Key);
            actions.ForEach(a =>
            {
                error.Append(
                    $" | Id : {a.Id}, Action Name: {a.Action}, Controller Name : {a.Controller}, Location : {a.Area}. ");
            });
        });
        var maxId = controllerActionlist.Max(x => x.Id);
        error.Append(
            "PLease consider changing the the duplicated id - Here are some options to choose from : Id {");
        for (int i = 1, j = 1; i < maxId + 5; i++)
        {
            if (actionIds.Contains(i)) continue;
            if (j < 5)
            {
                error.Append(i + ",");
                j++;
            }
            else
            {
                error.Append(i + "}");
                break;
            }
        }
        throw new Exception(
            $"There are more than one action duplicated with the same Id, The action data are as below : {error}");
    }
}

我可能会在数据库中添加所有这些数据,这样我就可以从数据库中的一个id中识别出一个动作:)

现在它运作良好。

答案 1 :(得分:0)

如果我理解正确,您正在尝试为每个页面/视图创建一个id,并在页面/视图中使用它来动态设置css类,以便将菜单选项卡设置为活动状态。如果是这样的话......不是试图在Controller中设置ID,而是仅使用以下代码创建一个共享视图 - 如下所示....

在View中编写以下Razor / C#代码。

    @{ 
        var iPageId = 0
        var sViewPath = ((System.Web.Mvc.BuildManagerCompiledView)ViewContext.View).ViewPath;
        
        //for example
        if (sViewPath.ToLower.IndexOf("admin") >= 0)
        {
          iPageId = 1;
        }
        else if (sViewPath.ToLower.IndexOf("dashboard") >= 0)
        {
          iPageId = 2;
        }
        else if (sViewPath.ToLower.IndexOf("vessels") >= 0)
        {
          iPageId = 3;
        }
        else if (sViewPath.ToLower.IndexOf("reports") >= 0)
        {
          iPageId = 4;
        }
    }

使用以下代码段在主视图中渲染共享视图。

@Html.Partial("~/Views/Menu/_SharedViewName.cshtml")

然后,您应该能够在主页面/视图中的任何位置访问 iPageId 变量,并相应地设置CSS类。