如何包含Partial但仅在尚未包含的情况下?

时间:2015-02-27 15:26:50

标签: asp.net-mvc knockout.js partial-views

我将ASP.NET MVC5knockout.js一起使用。我有几个knockout.js模板,或者部分视图。当我在视图或部分视图中有一个需要一个或多个特定模板的组件时,我会在Html.Partial中包含相应的模板。但是,我需要解决一个问题:这样,如果组件本身是部分的,并且我在视图中包含两个或更多组件,模板将被包含两次或更多次,这是不可取的。 / p>

我想实现这一点,每当我需要包含部分模板时,我不必担心它们是否已被包括在内。我可以将相同的部分模板包含两到三次,但最后,它只会在渲染视图中出现一次。

这个问题是否存在任何形式的第三方解决方案?

2 个答案:

答案 0 :(得分:1)

我有类似的问题。这就是我解决它的方式。我不喜欢这个解决方案,但它确实有效。如果有更好的方式,我会喜欢听到它。

public static class PartialExtension
    {
        public static void AddPartial(this HtmlHelper html, string partialLocation)
        {
            //Get a name for the template.  This is used to identify the template and
            //to ensure that a blank location has not been sent it.
            var partialName = Path.GetFileNameWithoutExtension(partialLocation);
            if (partialName == null)
                throw new Exception("The partial location can not be null");

            //Get the extension and directory.  If the location doesn't specify
            //a directory, like the location is in the current directory, then
            //we need to remove the extension.  Not sure why, but html.Partial()
            //throws an exception if you don't.
            var extension = Path.GetExtension(partialLocation);
            var dir = Path.GetDirectoryName(partialLocation);
            if (string.IsNullOrWhiteSpace(dir) && string.IsNullOrWhiteSpace(extension) == false)
                partialLocation = partialLocation.Replace(extension, "");

            var tmpBag = html.ViewBag;
            tmpBag.TbdTemplates = tmpBag.TbdTemplates as Dictionary<string, MvcHtmlString> ?? new Dictionary<string, MvcHtmlString>();

            //Only add this template once.
            if (((Dictionary<string, MvcHtmlString>)tmpBag.TbdTemplates).ContainsKey(partialName)) return;

            //FYI: because html.Partial can call this recursively, we want to set the item in the dictionary
            //as soon as possible.  Then we call Partial().  The final call to that method will be what is 
            //set as the value in the dictionary.
            ((Dictionary<string, MvcHtmlString>)tmpBag.TbdTemplates)[partialName] = MvcHtmlString.Create("");

            var tmpHtml = html.Partial(partialLocation, html.ViewData);
            ((Dictionary<string, MvcHtmlString>)tmpBag.TbdTemplates)[partialName] = tmpHtml;
        }

        public static MvcHtmlString WritePartials(this HtmlHelper html)
        {
            var tmpBag = html.ViewBag;
            tmpBag.TbdTemplates = tmpBag.TbdTemplates as Dictionary<string, MvcHtmlString> ?? new Dictionary<string, MvcHtmlString>();

            if (tmpBag.TbdTemplates == null) return MvcHtmlString.Create("");

            var builder = new StringBuilder();
            foreach (var value in tmpBag.TbdTemplates.Values)
            {
                builder.Append(value);
            }

            return MvcHtmlString.Create(builder.ToString());
        }
    }

然后在我的_Layout.cshtml中。 (接近底部)

<div id="Partials" style="display: none;">
        @Html.WritePartials()
    </div>

答案 1 :(得分:0)

我知道Razor /部分视图无法解决此问题。

您应该查看旨在解决此问题的Knockout Components(在3.2版中引入)。

Knockout组件可以通过各种方式呈现模板和viewModel。模板和视图模型仅定义一次,并根据需要重复使用多次。

如果您使用像requireJS这样的模块加载器(Knockout允许使用任何加载器),它还可以根据需要动态加载模板和脚本。组件也可以嵌套和重用。这应该涵盖你的要求。