What is a good way to set the Item or DataSource attribute for a FieldRenderer?

The scenario is that I have many FieldRenderers. They should output data from different places, some of the elements of X and others from the element of Y. And they should output properties from the element of Z.

Assuming I have a public ItemX property from which I want to infer the property, any of the following will be OK. But I do not get any of them:

 <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 %>" /> 

If I add the MyFieldRenderer identifier to it and make the ugly figure below, I get the correct output:

 MyFieldRenderer.Item = ItemX; 

Should there be a better way to do this? I'm not sure if this is a Sitecore or WebForms issue.

+4
source share
3 answers

It is not possible to set the FieldRenderer data source for an object on the server side without using the code behind. This is a consequence of the work of WebForms. This issue is described in the Microsoft Knowledge Base article :

The displayed expression <% = ...%> is the equivalent of an inline code block that contains only the Response.Write (...) operator. This is the easiest way to display information, such as a single line, an int variable, or a constant. [...] Remember that the displayed expression cannot be used in the attributes of server controls. This is because the .NET Framework directly compiles the whole expression instead of displaying the content as an attribute value.

In other words, .NET wants to compile sc: FieldRenderer and therefore does not have access to the contents of the runtime <% = ItemX.Paths.FullPath%>. You can see this problem in a simpler form, trying to display:

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

which displays <% = DateTime.Now.ToString ()%> inside the text box. In short, you cannot get anything but a static string inside the server control attribute.


There are several possible solutions to this problem:

  • In your Page_Load method, set the "Item" field to the FieldRenderer field as you described. This is the best approach if the number of sublayers that should use this logic is limited.

  • You can subclass ItemXFieldRenderer that binds Item to ItemX:

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

    Then you can use this control anywhere in your solution where you want to display the field from ItemX. This is the best approach if a large number of sublayers should use this logic, and the number of elements that may be required for binding is very limited.

  • You can create a subclass of FieldRenderer that parses a string property and uses logic to match the string value to the correct element.

  • If the path to ItemX is constant, you can set the full path in the Datasource property as follows:

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

    You can also use a relative path. For example, if a context element has a child folder called Sources, which in turn has a Default child element, you can reference this syntax in your field field:

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

    In my testing, evaluating a data source is not case sensitive, and Query Sitecore expressions such as "../ .." and "// * [@@ name =" value "] do not work.

  • You can use data binding to force ASCX to read the property, as recommended in this Threads :

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

    And in the code, add

     myRenderer.DataBind(); 

    With this last approach, you still use codebehind, but the solution that FieldRenderer uses is now contained in the markup. And as Christian Hagelid points out, you can call this.DataBind () on a sublayout to force the DataBind to execute recursively on all the controls on the page.

  • The ASP.NET ExpressionBuilder syntax can be used to centralize the location of your data source paths. There are three ways to do this:

    • Puts your paths in Web.config. Add this to the <AppSettings> Web.config section:

      <add key="ItemX" value="/sitecore/content/path/to/itemx" />
      Then set the DataSource attribute to:

      DataSource=<%$ AppConfig: ItemX %>

    • Put the paths in the .resx resource file in App_GlobalSettings. If the file is called Paths.resx, you can access its settings using this syntax:

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

    • You can build an ExpressionBuilder class to build logic to translate a string value into a path. Note that ExpressionBuilder is evaluated during Parse, so you will not have access to the Sitecore context. It doesn't look simple: the expression builder must be specified in Web.config, and the code must be in App_Code.

+7
source

If you have many FieldRenderer controls and want to contain logic inside the markup, you can use the expression <% # ...%> and just call this.DataBind (); at the end of the page. Loading. Then all controls inside your user control will be bound.

+4
source

I understand that you want to be able to do this in the interface, as in the MVC style, and not in the code, but this script seems to mean that the FieldRenderer frontend may not be the best tool, I obviously saw the code, which you wrote in your answer, but why not do it then, everything is in the interface:

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

eg.

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

Source: https://habr.com/ru/post/1446530/


All Articles