如何使用插件中的视图文件覆盖nopcommerce视图文件?

我试图覆盖位于以下位置的nopcommerce视图:

Nop.Admin/Views/Category/Tree.cshtml 

我在插件文件夹中开发了一个视图:

 Views/Misc/Tree.cshtml 

我该怎么做?

试试这篇我写过的详细文章: 3种在nopCommerce插件中显示视图的方法(嵌入式资源,主题覆盖和自定义视图引擎)

@ wooncherk的自定义视图引擎非常适合准备我们的视图,以便将来轻松覆盖。 但是,当涉及覆盖现有核心视图时,它无法实现,因为nopCommerce使管理视图优先于我们的自定义视图。 这可以在GetPath()的虚方法GetPath()Nop.Web.Framework.Themes.ThemeableVirtualPathProviderViewEngine.cs 。 对于那些想知道的人, ThemeableVirtualPathProviderViewEngine是由ThemeableRazorViewEngineinheritance的类, ThemeableRazorViewEngine后者又由@wooncherk的CustomViewEngine类inheritance。

ThemeableVirtualPathProviderViewEngine 参考上面关于ThemeableVirtualPathProviderViewEngine的屏幕截图,如箭头所示,这两行确认管理视图的优先级始终高于我们的自定义视图

我设法扩展@wooncherk的自定义视图引擎方法,以满足覆盖现有管理核心视图的需求。 这涉及覆盖虚拟方法GetPath()并将其复制到CustomViewEngine类中。 在这一点上,删除两个罪魁祸首甚至整个小黑客代码块似乎是合乎逻辑的,但不要,它会导致exception

 The model item passed into the dictionary is of type 'System.Collections.Generic.List`1[Nop.Admin.Models.Cms.RenderWidgetModel]', but this dictionary requires a model item of type 'System.Collections.Generic.List`1[Nop.Web.Models.Cms.RenderWidgetModel]'. 

新的CustomViewEngine将如下:

 public class CustomViewEngine: ThemeableRazorViewEngine { private readonly string[] _emptyLocations = null; public CustomViewEngine() { PartialViewLocationFormats = new[] { "~/Administration/CustomExtension/Views/{1}/{0}.cshtml", "~/Administration/CustomExtension/Views/Shared/{0}.cshtml" }; ViewLocationFormats = new[] { "~/Administration/CustomExtension/Views/{1}/{0}.cshtml", "~/Administration/CustomExtension/Views/Shared/{0}.cshtml" }; } protected override string GetPath(ControllerContext controllerContext, string[] locations, string[] areaLocations, string locationsPropertyName, string name, string controllerName, string theme, string cacheKeyPrefix, bool useCache, out string[] searchedLocations) { searchedLocations = _emptyLocations; if (string.IsNullOrEmpty(name)) { return string.Empty; } string areaName = GetAreaName(controllerContext.RouteData); //little hack to get nop's admin area to be in /Administration/ instead of /Nop/Admin/ or Areas/Admin/ if (!string.IsNullOrEmpty(areaName) && areaName.Equals("admin", StringComparison.InvariantCultureIgnoreCase)) { var newLocations = areaLocations.ToList(); newLocations.Insert(0, "~/Administration/Views/{1}/{0}.cshtml"); newLocations.Insert(0, "~/Administration/Views/Shared/{0}.cshtml"); //Insert your custom View locations to the top of the list to be given a higher precedence newLocations.Insert(0, "~/Administration/CustomExtension/Views/{1}/{0}.cshtml"); newLocations.Insert(0, "~/Administration/CustomExtension/Views/Shared/{0}.cshtml"); areaLocations = newLocations.ToArray(); } bool flag = !string.IsNullOrEmpty(areaName); List viewLocations = GetViewLocations(locations, flag ? areaLocations : null); if (viewLocations.Count == 0) { throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, "Properties cannot be null or empty.", new object[] { locationsPropertyName })); } bool flag2 = IsSpecificPath(name); string key = CreateCacheKey(cacheKeyPrefix, name, flag2 ? string.Empty : controllerName, areaName, theme); if (useCache) { var cached = ViewLocationCache.GetViewLocation(controllerContext.HttpContext, key); if (cached != null) { return cached; } } if (!flag2) { return GetPathFromGeneralName(controllerContext, viewLocations, name, controllerName, areaName, theme, key, ref searchedLocations); } return GetPathFromSpecificName(controllerContext, name, key, ref searchedLocations); } } 

请注意,在罪魁祸首行下方添加了两行,以使我们的自定义视图具有更高的优先级。


最后,我们需要修改RouteProvider.cs

 public class RouteProvider : IRouteProvider { public void RegisterRoutes(RouteCollection routes) { //Insert our CustomViewEngine into the top of the System.Web.Mvc.ViewEngines.Engines Collection to be given a higher precedence System.Web.Mvc.ViewEngines.Engines.Insert(0, new CustomViewEngine()); } public int Priority { get { return 1; } } } 

就是这样。 现在将自定义视图/部分视图放入视图位置,在这种情况下它们是

 ~/Administration/CustomExtension/Views/{1}/{0}.cshtml ~/Administration/CustomExtension/Views/Shared/{0}.cshtml 

其中{1}是您要覆盖的控制器的名称,{0}是您要覆盖的视图/局部视图的名称。

例如,如果要覆盖Nop.Admin/Views/Category/Tree.cshtml ,请将自定义Tree.cshtml放在Nop.Admin/CustomExtension/Views/Category/Tree.cshtml

Twisted Whisper有正确的答案,但我想我会分享一个博客文章的链接,更深入地讨论这个问题(更多地讨论自定义视图引擎如何工作以及使用这种技术的其他优点),如下所示:

点击此处查看深度讨论帖