MVC3 - render view that is not a method in a contr

2019-08-17 02:36发布

问题:

I don't know how to best describe my requirement, but here goes. I'm trying to render a view from the following controller/model in a nopCommerce application:

CustomerController.cs snippet:

[NonAction]
protected CustomerNavigationModel GetCustomerNavigationModel(Customer customer)
{
   var model = new CustomerNavigationModel();
   model.HideAvatar = !_customerSettings.AllowCustomersToUploadAvatars;
   model.HideRewardPoints = !_rewardPointsSettings.Enabled;
   model.HideForumSubscriptions = !_forumSettings.ForumsEnabled || !_forumSettings.AllowCustomersToManageSubscriptions;
   model.HideReturnRequests = !_orderSettings.ReturnRequestsEnabled || _orderService.SearchReturnRequests(customer.Id, 0, null).Count == 0;
   model.HideDownloadableProducts = _customerSettings.HideDownloadableProductsTab;
   model.HideBackInStockSubscriptions = _customerSettings.HideBackInStockSubscriptionsTab;
   return model;
}

CustomerNavigationModel.cs:

public partial class CustomerNavigationModel : BaseNopModel
{
    public bool HideInfo { get; set; }
    public bool HideAddresses { get; set; }
    public bool HideOrders { get; set; }
    public bool HideBackInStockSubscriptions { get; set; }
    public bool HideReturnRequests { get; set; }
    public bool HideDownloadableProducts { get; set; }
    public bool HideRewardPoints { get; set; }
    public bool HideChangePassword { get; set; }
    public bool HideAvatar { get; set; }
    public bool HideForumSubscriptions { get; set; }

    public CustomerNavigationEnum SelectedTab { get; set; }
 }

public enum CustomerNavigationEnum
{
    Info,
    Addresses,
    Orders,
    BackInStockSubscriptions,
    ReturnRequests,
    DownloadableProducts,
    RewardPoints,
    ChangePassword,
    Avatar,
    ForumSubscriptions
}

MyAccountNavigation.cshtml snippet:

 @model CustomerNavigationModel
 @using Nop.Web.Models.Customer;
 @if (!Model.HideInfo)
 {
      <li><a href="@Url.RouteUrl("CustomerInfo")" class="@if (Model.SelectedTab == CustomerNavigationEnum.Info)
          {<text>active</text>}
          else
          {<text>inactive</text>}">@T("Account.CustomerInfo")</a></li>}

Views: @Html.Partial("MyAccountNavigation", Model.NavigationModel, new ViewDataDictionary())

I am aware that it is unable to render MyAccountNavigation because it doesn't exist in the controller. However, depending on which page the syntax is placed it works. So is there a way to achieve that without changing the code in the controller? Thanks in advance.

回答1:

MVC looks for the partial view in a specific order. For your partial view to work, you need to place MyAccountNavigation.cshtml' into~/Views/Shared/`

I've looked at the source and this is what happens:

 public RazorViewEngine(IViewPageActivator viewPageActivator)
            : base(viewPageActivator)
        {
            AreaViewLocationFormats = new[]
            {
                "~/Areas/{2}/Views/{1}/{0}.cshtml",
                "~/Areas/{2}/Views/{1}/{0}.vbhtml",
                "~/Areas/{2}/Views/Shared/{0}.cshtml",
                "~/Areas/{2}/Views/Shared/{0}.vbhtml"
            };
            AreaMasterLocationFormats = new[]
            {
                "~/Areas/{2}/Views/{1}/{0}.cshtml",
                "~/Areas/{2}/Views/{1}/{0}.vbhtml",
                "~/Areas/{2}/Views/Shared/{0}.cshtml",
                "~/Areas/{2}/Views/Shared/{0}.vbhtml"
            };
            AreaPartialViewLocationFormats = new[]
            {
                "~/Areas/{2}/Views/{1}/{0}.cshtml",
                "~/Areas/{2}/Views/{1}/{0}.vbhtml",
                "~/Areas/{2}/Views/Shared/{0}.cshtml",
                "~/Areas/{2}/Views/Shared/{0}.vbhtml"
            };

            ViewLocationFormats = new[]
            {
                "~/Views/{1}/{0}.cshtml",
                "~/Views/{1}/{0}.vbhtml",
                "~/Views/Shared/{0}.cshtml",
                "~/Views/Shared/{0}.vbhtml"
            };
            MasterLocationFormats = new[]
            {
                "~/Views/{1}/{0}.cshtml",
                "~/Views/{1}/{0}.vbhtml",
                "~/Views/Shared/{0}.cshtml",
                "~/Views/Shared/{0}.vbhtml"
            };
            PartialViewLocationFormats = new[]
            {
                "~/Views/{1}/{0}.cshtml",
                "~/Views/{1}/{0}.vbhtml",
                "~/Views/Shared/{0}.cshtml",
                "~/Views/Shared/{0}.vbhtml"
            };

            FileExtensions = new[]
            {
                "cshtml",
                "vbhtml",
            };
        }

We are interested in AreaPartialViewLocationFormats and PartialViewLocationFormats.

This explains why your view is found when you try to use it within Customer related views, and it doesn't work anywhere else.



回答2:

Whatever I understand from your question is you need to execute "MyAccountNavigation" partial view from many pages and for that you can put this partial view in Shared folder.

Please correct me if I am wrong.

Edited text

BaseController :

ExcecuteCore method

you can store your menu or that model in ViewBag like

var customerNavigationModel = assigned your value;
ViewBag.MenuData = customerNavigationModel;

From view

@{Html.RenderPartial("MyAccountNavigation", ViewBag.MenuData);}