5

假设我希望每个页面都有一个不同的主图像,位于页面标题上方。另外,我需要将页面特定的图像放在左侧栏中,将页面特定的文本放在右侧栏中。在左右栏中,我还想要图层特定的内容。

如果不为站点中的每个页面创建一个图层,我无法看到如何实现这一点,但是我最终会得到大量图层,这些图层只提供一个看起来太复杂的页面。

我错过了什么?

如果有一种使用内容部分的方法,如果你能指出我的教程、博客、视频来帮助我解决这个问题,那就太好了。

笔记:

Sitefinity 在这类事情上做得很好,但我发现 Orchard 创建模块要简单得多,而且我发现它是 MVC 更容易。

Orchard 是免费的,我理解(并欣赏)这一点。只是希望随着产品的发展,这种事情会变得更容易吗?

换句话说,我希望世界上最好的……

4

2 回答 2

5

1.5 的作品中有一个功能可以使这更容易,但与此同时,您已经可以通过一点点代码轻松地让它工作。您应该首先将您需要的字段添加到您的内容类型。然后,您将使用放置将它们发送到顶级布局区域。开箱即用,展示位置仅针对本地内容区域,但这是我们可以使用 Pete Hurst(又名 randompete)的一些代码来解决的问题。这是代码:

ZoneProxyBehavior.cs:
=====================

using System;
using System.Collections.Generic;
using System.Linq;
using ClaySharp;
using ClaySharp.Behaviors;
using Orchard.Environment.Extensions;

namespace Downplay.Origami.ZoneProxy.Shapes {
    [OrchardFeature("Downplay.Origami.ZoneProxy")]
    public class ZoneProxyBehavior : ClayBehavior {

        public IDictionary<string, Func<dynamic>> Proxies { get; set; }

        public ZoneProxyBehavior(IDictionary<string, Func<dynamic>> proxies) {
            Proxies = proxies;
        }

        public override object GetMember(Func<object> proceed, object self, string name) {

            if (name == "Zones") {
                return ClayActivator.CreateInstance(new IClayBehavior[] {                
                    new InterfaceProxyBehavior(),
                    new ZonesProxyBehavior(()=>proceed(), Proxies, self)
                });
            }

            // Otherwise proceed to other behaviours, including the original ZoneHoldingBehavior
            return proceed();
        }

        public class ZonesProxyBehavior : ClayBehavior {
            private readonly Func<dynamic> _zonesActivator;
            private readonly IDictionary<string, Func<dynamic>> _proxies;
            private object _parent;

            public ZonesProxyBehavior(Func<dynamic> zonesActivator, IDictionary<string, Func<dynamic>> proxies, object self) {
                _zonesActivator = zonesActivator;
                _proxies = proxies;
                _parent = self;
            }

            public override object GetIndex(Func<object> proceed, object self, IEnumerable<object> keys) {
                var keyList = keys.ToList();
                var count = keyList.Count();
                if (count == 1) {

                    // Here's the new bit
                    var key = System.Convert.ToString(keyList.Single());

                    // Check for the proxy symbol
                    if (key.Contains("@")) {
                        // Find the proxy!
                        var split = key.Split('@');
                        // Access the proxy shape
                        return _proxies[split[0]]()
                            // Find the right zone on it
                            .Zones[split[1]];
                    }
                    // Otherwise, defer to the ZonesBehavior activator, which we made available
                    // This will always return a ZoneOnDemandBehavior for the local shape
                    return _zonesActivator()[key];
                }
                return proceed();
            }

            public override object GetMember(Func<object> proceed, object self, string name) {
                // This is rarely called (shape.Zones.ZoneName - normally you'd just use shape.ZoneName)
                // But we can handle it easily also by deference to the ZonesBehavior activator
                return _zonesActivator()[name];
            }
        }
    }
}

和:

ZoneShapes.cs:
==============


using System;
using System.Collections.Generic;
using Orchard.DisplayManagement.Descriptors;
using Orchard;
using Orchard.Environment.Extensions;

namespace Downplay.Origami.ZoneProxy.Shapes {
    [OrchardFeature("Downplay.Origami.ZoneProxy")]
    public class ZoneShapes : IShapeTableProvider {
        private readonly IWorkContextAccessor _workContextAccessor;
        public ZoneShapes(IWorkContextAccessor workContextAccessor) {
            _workContextAccessor = workContextAccessor;
        }

        public void Discover(ShapeTableBuilder builder) {

            builder.Describe("Content")
                .OnCreating(creating => creating.Behaviors.Add(
                    new ZoneProxyBehavior(
                        new Dictionary<string, Func<dynamic>> { { "Layout", () => _workContextAccessor.GetContext().Layout } })));
        }
    }

}

有了这个,您将能够在要寻址的区域名称前面使用顶级布局区域Layout@,例如Layout@BeforeContent:1.

于 2012-05-28T19:41:59.723 回答
4

附录:

我使用了 Bertrand Le Roy 的代码(制作 Pete Hurst 的代码)并用它创建了一个模块,然后添加了 3 个内容部分,它们都是 Core/Common 中正文部分的所有副本。

在同一个模块中,我创建了一个 ContentType 并向其中添加了我的三个自定义 ContentPart,加上自动路由和 bodypart 和标签等,一切使它就像 Orchard Pages ContentType 一样,只有更多的部分,每个都有自己的形状。

我将我的 ContentType 称为视图。

因此,您现在可以使用视图为您的站点创建页面。然后,您使用 ZoneProxy 将自定义 ContentPart 形状(Parts_MainImage、Parts_RightContent、Parts_LeftContent)分流到我需要它们的任何区域中。完成工作。

不完全是 Sitefinity,但正如比尔所说,足够好。

您必须创建自己的 ContentParts 来复制 BodyPart 而不仅仅是使用 TextField,原因是所有 TextFields 都具有相同的形状,因此如果您使用 ZoneProxy 放置它们,它们最终都会在同一个区域中。即,您构建自定义 ContentParts 只是为了获得形状。因为它是您使用 ZoneProxy 代码放置的形状。

一旦我对此进行了测试,我会将它作为一个模块上传到 Orchard Gallery。它将被称为 Wingspan.Views。

我在 2012 年 6 月 12 日之前都在休假,所以不要指望月底之前。

但本质上,使用 Pete Hurst 的代码,这就是我解决问题的方法。

编辑:

我可以通过创建三个内容部分(LeftContent、RightContent、MainImage 等)或任何需要的内容部分,然后将它们添加到 Page 内容类型来获得相同的结果。

这样,您只需添加所需的内容。

但是,拥有可以开箱即用的标准 ContentType 有一些优势。

例如,使用放置(Placement.info 文件)可以将 MainImage 内容部分用作页脚。即,名称可能应该是第 1 部分、第 2 部分等。

如果有一种方法可以为 TextField 生成的形状提供自定义名称,那么这些都不是必需的。这样,您可以根据需要添加尽可能多的 TextField,然后使用 ZoneProxy 代码放置它们。我不确定这是否可能。

于 2012-06-02T16:23:00.193 回答