簡體   English   中英

如何使用插件中的視圖文件覆蓋nopcommerce視圖文件?

[英]How to override a nopcommerce view file with a view file inside the plugin?

我想覆蓋位於以下位置的nopcommerce視圖:

Nop.Admin/Views/Category/Tree.cshtml  

以及我在我的插件文件夾中開發的視圖:

Views/Misc/Tree.cshtml

我該怎么做?

@wooncherk的自定義視圖引擎非常適合准備我們的視圖,以便將來輕松覆蓋。 但是,當涉及覆蓋現有核心視圖時,它不足,因為nopCommerce給予管理視圖優先於我們的自定義視圖。 這可以在GetPath()的虛方法GetPath()Nop.Web.Framework.Themes.ThemeableVirtualPathProviderViewEngine.cs 對於那些想知道的人, ThemeableVirtualPathProviderViewEngine是由ThemeableRazorViewEngine繼承的類, ThemeableRazorViewEngine后者又由@wooncherk的CustomViewEngine類繼承。

ThemeableVirtualPathProviderViewEngine 參考上面關於ThemeableVirtualPathProviderViewEngine的屏幕截圖,如箭頭所示,這兩行確認管理視圖的優先級始終高於我們的自定義視圖

我設法擴展@wooncherk的自定義視圖引擎方法,以滿足覆蓋現有管理核心視圖的需求。 這涉及覆蓋虛擬方法GetPath()並將其復制到CustomViewEngine類中。 在這一點上,刪除兩個罪魁禍首甚至整個小黑客代碼塊似乎是合乎邏輯的,但不要,它會導致異常

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<ViewLocation> 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}是您要覆蓋的Controller的名稱,{0}是您要覆蓋的視圖/局部視圖的名稱。

例如,如果要覆蓋Nop.Admin/Views/Category/Tree.cshtml ,請將自定義Tree.cshtml放在Nop.Admin/CustomExtension/Views/Category/Tree.cshtml

Twisted Whisper有正確的答案,但我想我會分享一個博客文章的鏈接,深入討論這個(更多關於自定義視圖引擎如何工作以及使用這種技術的其他優點)在這里看到:

點擊此處查看深度討論帖

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM