设置FieldRenderer的Item或DataSource属性的好方法是什么?

时间:2012-11-16 19:34:35

标签: asp.net sitecore webforms sitecore6

场景是我有很多FieldRenderers。这些应该从各个地方输出数据,一些来自项目X,另一些来自项目Y.并且应该从项目Z输出属性。

假设我有一个公共属性ItemX,我想从中输出属性,以下任何一个都可以。但我没有得到任何输出:

<sc:FieldRenderer runat="server" FieldName="Logo" DataSource="<%# ItemX %>" />
<sc:FieldRenderer runat="server" FieldName="Logo" DataSource="<%= ItemX.Paths.FullPath %>" />
<sc:FieldRenderer runat="server" FieldName="Logo" Item="<%# ItemX %>" />
<sc:FieldRenderer runat="server" FieldName="Logo" Item-ID="<%# ItemX.ID %>" />
<sc:FieldRenderer runat="server" FieldName="Logo" Item-ID-Guid="<%# ItemX.ID.Guid %>" />

如果我向其添加ID MyFieldRenderer并执行下面的丑陋部分,我会得到正确的输出:

MyFieldRenderer.Item = ItemX;

必须有更好的方法吗?我不确定这是Sitecore特定的还是WebForms问题。

3 个答案:

答案 0 :(得分:7)

如果不使用代码,则无法将FieldRenderer的数据源设置为服务器端对象。这是WebForms工作方式的结果。该问题在Microsoft Knowledge Base article

中进行了描述
  

&lt;%= ...%&gt;显示表达式相当于仅包含Response.Write(...)语句的嵌入式代码块。这是显示单个字符串,int变量或常量等信息的最简单方法。 [...] 请记住,显示表达式不能用于服务器控件的属性。这是因为.NET Framework直接编译整个表达式而不是显示内容作为属性的值。

换句话说,.NET想要编译sc:FieldRenderer,因此无法访问&lt;%= ItemX.Paths.FullPath%&gt;的运行时内容。您可以通过尝试显示以简单的形式查看此问题:

<asp:TextBox runat="server" Text="<%= DateTime.Now.ToString() %>" />

在文本框内呈现&lt;%= DateTime.Now.ToString()%&gt; 。简而言之,除了服务器控件属性中的静态字符串之外,您无法获得任何其他内容。


此问题有几种可能的解决方案:

  1. 在Page_Load方法中,如您所述,设置FieldRenderer的Item字段。如果需要使用此逻辑的子布局数量有限,这是最佳方法。

  2. 您可以创建一个将Item绑定到ItemX的ItemXFieldRenderer子类:

     class ItemXFieldRenderer: FieldRenderer {
       public ItemXFieldRenderer() {
           Item = [code to retrieve ItemX];
       }
     }
    

    然后,您可以在解决方案的任何位置使用此控件,以便从ItemX渲染字段。如果大量子布局需要使用此逻辑,并且您可能需要绑定的项目数量非常有限,这是最好的方法。

  3. 您可以创建FieldRenderer的子类,该子类解析字符串属性并使用逻辑将字符串值映射到正确的项目。

  4. 如果ItemX的路径是常量,您可以在数据源属性中设置完整路径,如下所示:

    <sc:FieldRenderer runat="server" FieldName="Logo"
    DataSource="/sitecore/context/home/some/item" />
    

    您还可以使用相对路径。例如,如果上下文项具有名为“Sources”的子文件夹,而子文件夹又具有子项“Default”,则可以使用以下语法在FieldRenderer中引用:

    <sc:FieldRenderer runat="server" FieldName="Logo"
    DataSource="sources/default" />
    

    根据我的测试,数据源的评估不区分大小写,Sitecore查询表达式如“../ ..”和“// * [@@ name ='value']”不起作用。

  5. 您可以使用数据绑定强制ASCX读取属性,如Forums thread中所述:

    <sc:FieldRenderer id="myRenderer" FieldName="Logo" 
    DataSource=<%# ItemX.Paths.FullPath %> />
    

    在代码隐藏中,添加

    myRenderer.DataBind(); 
    

    使用最后一种方法,您仍然使用代码隐藏,但是决定哪个FieldRenderer使用哪个项目现在包含在标记中。而作为Christian Hagelid points out,您可以在子布局上调用this.DataBind()来强制DataBind以递归方式对页面上的所有控件执行。

  6. 您可以使用ASP.NET的ExpressionBuilder语法来集中数据源路径的位置。有三种方法可以做到这一点:

    • 将路径放在Web.config中。将其添加到&lt; AppSettings&gt; Web.config部分:

      <add key="ItemX" value="/sitecore/content/path/to/itemx" />
      然后将DataSource属性设置为:

      DataSource=<%$ AppConfig: ItemX %>

    • 将路径放在App.GlobalSettings中的.resx资源文件中。如果文件名为Paths.resx,则可以使用以下语法访问其设置:

      DataSource=<%$ Resources: Paths,ItemX %>

    • 您可以构建一个ExpressionBuilder类来构建逻辑以将字符串值转换为路径。请注意,ExpressionBuilder在Parse时进行评估,因此您无权访问Sitecore上下文。这看起来并不简单:表达式构建器需要在Web.config中引用,代码需要驻留在App_Code中。

答案 1 :(得分:4)

如果你有很多FieldRenderer控件,并且你想在标记中包含逻辑,那么你可以使用&lt;%#...%&gt;表达式,只需调用this.DataBind();在Page.Load的末尾。然后,它将绑定用户控件中的所有控件。

答案 2 :(得分:1)

我知道你希望能够像在MVC风格中那样在前端执行此操作,而不是在代码隐藏中执行此操作,但是这种情况似乎表明前端FieldRenderer控件可能不是正确的工具。我很明显看到你在答案中写的代码,但为什么不这样做,所有这些都在前端:

<%= FieldRenderer.Render(item, "field name") %>

E.g。

<%= FieldRenderer.Render(ItemX, "Logo") %>