场景是我有很多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问题。
答案 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; 。简而言之,除了服务器控件属性中的静态字符串之外,您无法获得任何其他内容。
此问题有几种可能的解决方案:
在Page_Load方法中,如您所述,设置FieldRenderer的Item字段。如果需要使用此逻辑的子布局数量有限,这是最佳方法。
您可以创建一个将Item绑定到ItemX的ItemXFieldRenderer子类:
class ItemXFieldRenderer: FieldRenderer {
public ItemXFieldRenderer() {
Item = [code to retrieve ItemX];
}
}
然后,您可以在解决方案的任何位置使用此控件,以便从ItemX渲染字段。如果大量子布局需要使用此逻辑,并且您可能需要绑定的项目数量非常有限,这是最好的方法。
您可以创建FieldRenderer的子类,该子类解析字符串属性并使用逻辑将字符串值映射到正确的项目。
如果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']”不起作用。
您可以使用数据绑定强制ASCX读取属性,如Forums thread中所述:
<sc:FieldRenderer id="myRenderer" FieldName="Logo"
DataSource=<%# ItemX.Paths.FullPath %> />
在代码隐藏中,添加
myRenderer.DataBind();
使用最后一种方法,您仍然使用代码隐藏,但是决定哪个FieldRenderer使用哪个项目现在包含在标记中。而作为Christian Hagelid points out,您可以在子布局上调用this.DataBind()来强制DataBind以递归方式对页面上的所有控件执行。
您可以使用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") %>