如何在Ektron

时间:2016-10-12 18:16:29

标签: content-management-system ektron

如何在Ektron版本中显示使用SmartForm创建的项目列表:9.00 SP3(Build 9.0.0.249)?

我创建了一个SmartForm,用户可以在其中输入可用职位的详细信息。现在我想在列表中显示那些位置,即可用的工作。然后当他们点击一个链接时,它会将他们带到该工作的详细信息。

我对Ektron没有任何经验,所以我希望这不是一个愚蠢的问题,我需要将其分解为非常基本的水平。

1 个答案:

答案 0 :(得分:1)

编辑:您可以在using strongly typed objects with Ektron Smart Forms at Thomas Higginbotham's blog找到更详尽的信息。

POST:

我在下面创建的示例是用于输出列表中的图像,就好像我要创建一个库。请记住,当实际创建一个图库时,我会做其他事情,因此在这方面,这绝不是完整的代码。然而,它是如何以最可能的.NET方式从Ektron检索和处理内容的一个非常好的简单示例(没有更多的关注点分离)。

首先,我有一些推荐的阅读材料。 Ken McAndrew(长期的Ektron开发者和现在的Sitecore开发者)将a nice set of posts about a class you can use to obtain Ektron's Smart Form content as .NET objects放在一起,使他们更容易使用。我建议使用Ken的版本(博客文章中的链接)。

还有a hangout featuring Bill Cava, original author of the method, Ken, and myself谈论这种方法,这可能会有所帮助。

我看了,我认为最初的网络研讨会已被删除。

无论如何,一旦你有内容类型代码,它就相对简单了。你想要:

  1. 为Smart Forms创建.NET模型
  2. 获取物品
  3. 将它们映射到ViewModel(可选)
  4. 将它们数据绑定到ListView或Repeater控件
  5. 为Smart Forms创建.NET模型

    为了开始这个,我为新闻摄影创建了一个相当简单的智能表格。它包含三个字段:

    1. 名称
    2. 说明(标题)
    3. 图片(为简单起见,存储为URL字符串,而不是<img />标记)
    4. Sample Smart Form: Press Photo

      接下来,点击&#34; XSD&#34; SmartForm数据设计视图中的按钮(您添加/管理字段的位置)并复制所有XSD代码。 (您将在下面的屏幕截图中看到XSD按钮,位于模态上方。)

      Sample Smart Form: XSD

      将其保存到文件中。我在C:\ContentTypes创建了一个文件夹,并在那里将文件添加为PressPhoto.xsd

      您希望运行file called XSD.exe(由Microsoft提供和记录,作为大多数Visual Studio安装的一部分)。这将使用XSD并为您生成一个C#类文件 - 这对于将Smart Form XML反序列化为.NET对象非常友好。

      在这里找到它(包含在Visual Studio 2015中):

      XSD.exe File Location

      但是,从命令行运行它是我感到痛苦的事情,因为我总是忘记它的相当冗长的路径。所以我创建了一个Batch文件来为我做大部分的脏工作。我按顺序写了它接受三个参数:

      1. XSD文件的路径
      2. 我想要存储生成的类文件的输出路径
      3. 我想要生成的类的名称空间(提示:我总是将名称空间设置为包含智能表单的名称 - 如果您为多个智能表单生成类,这可以防止冲突)
      4. 这里是代码和执行它的命令的屏幕截图。

        @ECHO OFF
        
        SET xsdExePath="C:\Program Files (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.1 Tools\xsd.exe"
        SET xsdFilePath="%~f1"
        SET outFolderPath="%~f2"
        SET ns=%3
        
        %xsdExePath% /c %xsdFilePath% /o:%outFilePath% /l:CS /n:%ns%
        

        Executing the Batch file

        这将在我的C:\ ContentTypes \目录中生成一个名为PressPhoto.cs的文件。

        进入我的Ektron项目,我将在我的App_Code文件夹的目录中添加Ken的SmartForm类(在他上面的博客中引用)和我的新PressPhoto类。就像这样(App_Code / CSCode下面的文件夹结构取决于你,但保持它的组织是为了你自己的理智):

        Placement of classes within App_Code/CSCode

        为您要通过API提取的每个智能表单添加一个类(对我而言,所有智能表单)。

        我知道这似乎是很多准备工作,与其他一些更现代化的系统相比,它确实如此。但是一旦你习惯了,这将极大地帮助你。

        获取项目(并映射到ViewModel)

        既然您已经基本上创建了自己的API来获取项目(替代方案是XML Transforms,顺便说一句),那么您已准备好使用它们。

        我更喜欢创建自己的&#34;经理&#34; class以及ViewModel。如果您不喜欢不同的方法,那么至少会为您提供示例代码以便朝着自己的方向前进。

        我正在对代码进行内联评论,以便您可以在上下文中阅读它们。

        查看模型 - 非常基本

        namespace MyProject.ViewModels
        {
            /// <summary>
            /// Provides the fields necessary to display a PressPhoto Smart Form to the site.
            /// </summary>
            public class PressPhotoViewModel
            {
                public string Title { get; set; }
                public string Description { get; set; }
                public string ImageUrl { get; set; }
                public string ContentUrl { get; set; }
                public long ContentId { get; set; }
                public PressPhotoViewModel()
                {
        
                }
            }
        }
        

        &#34;经理&#34;因此我尽可能少地将代码放入代码隐藏中。我所有的PressPhoto逻辑都是一个不错的集中位置。

        using Ektron.Cms;
        using Ektron.Cms.Content;
        using Ektron.Cms.Common;
        using Ektron.Cms.Framework.Custom;
        using MyProject.SmartForms.PressPhoto;
        using MyProject.ViewModels;
        using System.Collections.Generic;
        using System.Linq;
        
        namespace MyProject.Managers
        {
            /// <summary>
            /// Provides CRUD operations for managing PressPhoto objects within the CMS.
            /// </summary>
            public class PressPhotoManager
            {
                /* 
                 * "root" is the default root element of the Smart Form XML. 
                 * 
                 * If you've changed this, your code will be different. Most people don't, 
                 * so I'm going with the lowest-common-denominator example.
                 * 
                 * I normally set the "root" to something else, and thus give it a more 
                 * meaningful class name. I also tend to load this manager via something more
                 * similar to a singleton, but for simplicity's sake...
                 */
                private SmartFormManager<root> pressPhotoManager = new SmartFormManager<root>();
        
                public PressPhotoManager()
                {
                    // Nothing needs done here for this example.
                }
        
                /*
                 * Usually, I'm not interested in writing information back to the DB, so
                 * I'm only going to include samples for GetItem and GetList (by folder) here.
                 */
        
                /// <summary>
                /// Retrieves a PressPhoto item by its Ektron Content ID
                /// </summary>
                /// <param name="ContentId">Ektron Smart Form Content Id</param>
                /// <returns>Press Photo ViewModel for display</returns>
                public PressPhotoViewModel GetItem(long ContentId)
                {
                    /*
                     * Get items - this returns an object that is the amalgamation of the standard 
                     * Ektron ContentData object and the deserialized Smart Form information.
                     * 
                     * The format is:
                     * * systemObject.Content = standard ContentData fields
                     * * systemOjbect.SmartForm = Smart Form fields
                     * 
                     * For some reason, the returned object in the custom class inherits from ContentData.
                     * This inheritance is probably not necessary and is also likely confusing. So only try 
                     * to use the fields within the containers listed above.
                     */
                    var systemObject = pressPhotoManager.GetItem(ContentId, false);
                    if (systemObject == null) return null;
        
        
                    /*
                     * I often want to map both Smart Form and ContentData fields to my output. This is where
                     * a ViewModel comes in handy - it normalizes the data to be rendered. So then I'm not 
                     * dealing with object.Content.* and object.SmartForm.* during rendering.
                     * 
                     * Another note: You might consider putting this mapping into a constructor in
                     * the ViewModel in order to avoid the repetition you'll find in the GetList method
                     * below.
                     */
                    return new PressPhotoViewModel()
                    {
                        ContentId = systemObject.Content.Id,
                        ContentUrl = systemObject.Content.Quicklink,
                        Title = systemObject.SmartForm.Name,
                        Description = systemObject.SmartForm.Caption,
                        ImageUrl = systemObject.SmartForm.Photo
                    };
                }
        
                /// <summary>
                /// Retrieves a list of PressPhoto by the containing Ektron Folder Id (non-recursive)
                /// </summary>
                /// <param name="FolderId">Ektron Folder Id</param>
                /// <returns>Enumerable of Press Photo ViewModel for display</returns>
                public IEnumerable<PressPhotoViewModel> GetList(long FolderId)
                {
                    /*
                     * There are several "Criteria" objects. This is the simplist, but they also exist
                     * for retrieving items from a Collection, from Taxonomy, or given a certain 
                     * Metadata property value.
                     */
                    var criteria = new ContentCriteria();
        
                    // Filter tells the API which folder to retrieve content from.
                    criteria.AddFilter(ContentProperty.FolderId, CriteriaFilterOperator.EqualTo, FolderId);
        
                    // Don't check sub-folders.
                    criteria.FolderRecursive = false;
        
                    /*
                     * Retrieve only 12. The default is 50. Get in the habit of setting this so you 
                     * don't grab 50 when you only need one.
                     */
                    criteria.PagingInfo = new PagingInfo(12);
        
                    // Only return metadata when you need it, for performance. Default here is false.
                    criteria.ReturnMetadata = false;
        
                    // Ordering FTW! Hopefully self-explanatory.
                    criteria.OrderByField = ContentProperty.Title;
                    criteria.OrderByDirection = EkEnumeration.OrderByDirection.Ascending;
        
                    // Same as above... 
                    var systemObjectList = pressPhotoManager.GetList(criteria);
                    if (systemObjectList == null || !systemObjectList.Any()) return null;
        
                    return systemObjectList.Select(p => new PressPhotoViewModel()
                    {
                        ContentId = p.Content.Id,
                        ContentUrl = p.Content.Quicklink,
                        Title = p.SmartForm.Name,
                        Description = p.SmartForm.Caption,
                        ImageUrl = p.SmartForm.Photo
                    });
                }
            }
        }
        

        数据绑定到列表控件

        为简单起见,我将把这段代码放入.NET用户控件中。

        标记:

        <%@ Control Language="C#" AutoEventWireup="true" CodeFile="Gallery.ascx.cs" Inherits="Components_Controls_Gallery" %>
        <asp:ListView ID="uxPhotoGallery" runat="server" ItemPlaceholderID="itemPlaceholder">
            <LayoutTemplate>
                <ul>
                    <asp:PlaceHolder ID="itemPlaceholder" runat="server" />
                </ul>
            </LayoutTemplate>
            <ItemTemplate>
                <li>
                    <%-- 
                        I'm mixing up two different ways of referencing the incoming data. One is by casting
                        the DataItem to the incoming type, which gives you intellisense access to the properties.
        
                        The other is more of a dictionary approach in which you have to type out the property name 
                        as a string.
        
                        I really like the casting approach, but it's mega-wordy.
                         --%>
                    <a href="<%#((MyProject.ViewModels.PressPhotoViewModel)Container.DataItem).ImageUrl %>">
                        <img src="<%#((MyProject.ViewModels.PressPhotoViewModel)Container.DataItem).ImageUrl %>" alt="<%#Eval("Description") %>" />
                        <div><%#Eval("Description") %></div>
                    </a>
                </li>
            </ItemTemplate>
        </asp:ListView>
        

        代码:

        using MyProject.Managers;
        using System;
        using System.Linq;
        
        public partial class Components_Controls_Gallery : System.Web.UI.UserControl
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                var pressPhotoManager = new PressPhotoManager();
        
                // Whichever folder Id... 
                var photos = pressPhotoManager.GetList(75);
        
                if (photos != null && photos.Any())
                {
                    uxPhotoGallery.DataSource = photos;
                    uxPhotoGallery.DataBind();
                }
            }
        }
        

        而且......应该这样做。无论如何,我知道如何最好的方式。肯定有一些方法需要更少的代码和准备,但这是我的首选,因为它让我尽可能地使用真正的.NET对象。虽然您可以使用LinqToXML或其他技术,但我更喜欢不使用它们,因为它需要您开发大量自己的XML知识,并且永远不会读取它,imo。

        快乐的编码。