Custom Content Module referencing other content module content?
Using the products module as a sample, I created another content based module. I need to add a custom field that will act as a "selector" from existing content. For example, when entering new content in this module, I want them to have a field that when they click, it brings up a list of news and they can choose the associated news articles. Is there any documentation on how I could accomplish this?
Hi Chris,
You will find similar implementation here.
Greetings,
Ivan Dimitrov
the Telerik team
Hi Ivan,
Thanks for the link. I've been playing with it but it looks like it applies to Sitefinity 3.x. Doesn't that work differently then 4.0?
Hi Chris,
In 4.0 you have to create a custom selector that is bound to the datasource of content items. You can take a look at this post which shows similar implementation - Thumbnail selector for news.
Regards,
Ivan Dimitrov
the Telerik team
Hi Ivan,
If I'm building this into my module rather then adding it as a field to an exisiting one, how do I define it in my definitions file? I figured I could build the selector in Web/UI/Admin, but how do I create the button inside the module that will load it? I created a new section using this code:
#region Relationships var relationshipsSection = new ContentViewSectionElement(detailView.Sections) Name = "RelationshipsSection", Title = Res.Get<KnowledgebaseResources>().KnowledgebaseRelationships, ResourceClassId = typeof(KnowledgebaseResources).Name, CssClass = "sfExpandableForm", ExpandableDefinitionConfig = Expanded = false ; detailView.Sections.Add(relationshipsSection); #endregionHello Chris,
1. You should create a custom filed control that will open a selector that will allow you to choose an image. You should inherit from FiledControl class.
2. You should create a custom DefinitionElement that inherits from FieldControlDefinitionElement
3. You should use your custom definition element in your module definition class
All the best,
Ivan Dimitrov
the Telerik team
Hi Ivan,
I'm sure that makes perfect sense to you since you have intimate knowledge of the product but "you should create a custom filed control that will open a selector" is where I'm stuck. Can you provide sample code with how to accomplish this? I've got the selector ready in accordance with Slavo's blog post. The textfield appears fine but the button to "select" is not showing up.
Chris
var newsField = new NewsFieldElement(knowledgebaseRelationshipsSection.Fields)
ID = "newsFieldControl",
FieldType = typeof(NewsField),
FieldVirtualPath = "~/Web/UI/Public/NewsSelector/NewsField.ascx",
DataFieldName = "newsRelationships",
DisplayMode = displayMode,
CssClass = "sfContentField"
;
knowledgebaseRelationshipsSection.Fields.Add(newsField);
is throwing this error:
Hello Chris,
Can you post the error that you are getting. There was a page or some link that you submitted and it crashed your last post.
Best wishes,
Ivan Dimitrov
the Telerik team
Hi Ivan,
Thanks for deleting that other post - I tried to copy just the text of the error message but looks like I grabbed more. Once I posted it, I couldn't delete it.
I updated my code according to your samples here: www.sitefinity.com/.../adding-image-selector-to-products-module.aspx
The error I'm getting now is:
Invalid resource name "Knowledgebase.Web.UI.Public.NewsField.ascx" for assembly "Knowledgebase, Version=1.0.4102.16495, Culture=neutral, PublicKeyToken=null" or empty template.
Stack Trace:
[ArgumentException: Invalid resource name "Knowledgebase.Web.UI.Public.NewsField.ascx" for assembly "Knowledgebase, Version=1.0.4102.16495, Culture=neutral, PublicKeyToken=null" or empty template.]
Telerik.Sitefinity.Web.UI.ControlUtilities.GetTemplate(String virtualPath, String resourceFileName, Type assemblyInfo, String templateDeclaration) +1077
Telerik.Sitefinity.Web.UI.ControlUtilities.GetControlTemplate(TemplateInfo info) +754
Telerik.Sitefinity.Web.UI.ControlUtilities.GetTemplate(TemplateInfo info) +786
Telerik.Sitefinity.Web.UI.SimpleView.get_LayoutTemplate() +184
Telerik.Sitefinity.Web.UI.SimpleView.get_Container() +40
Telerik.Sitefinity.Web.UI.SimpleView.CreateChildControls() +62
System.Web.UI.Control.EnsureChildControls() +182
System.Web.UI.Control.PreRenderRecursiveInternal() +73
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Control.PreRenderRecursiveInternal() +240
System.Web.UI.Page.ProcessRequestMain(Boolean includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint) +3914
I'm sure it's a simple miss somewhere as to why it can't find the NewsField.ascx file but I haven't been able to track it down.
My definition looks like this:
var newsField = new NewsFieldElement(knowledgebaseRelationshipsSection.Fields) ID = "newsFieldControl", DataFieldName = "newsRelationships", DisplayMode = displayMode, CssClass = "sfContentField" ; knowledgebaseRelationshipsSection.Fields.Add(newsField);
NewsFieldElement.cs:
using System;using System.Configuration;using Telerik.Sitefinity.Configuration;using Telerik.Sitefinity.Localization;using Telerik.Sitefinity.Web.UI;using Telerik.Sitefinity.Web.UI.Fields.Config;using Telerik.Sitefinity.Web.Configuration;using Telerik.Sitefinity.Web.UI.Extenders.Contracts;using Telerik.Sitefinity.Web.UI.Extenders.Config;namespace Knowledgebase.Web.UI.Public /// <summary> /// A configuration element used to persist the properties of <see cref="NewsFieldDefinition"/> /// </summary> public class NewsFieldElement : FieldControlDefinitionElement, INewsFieldDefinition #region Constructors /// <summary> /// Initializes a new instance of the <see cref="NewsFieldElement"/> class. /// </summary> /// <param name="parent">The parent.</param> public NewsFieldElement(ConfigElement parent) : base(parent) #endregion /// <summary> /// Gets an instance of the <see cref="NewsFieldDefinition"/> class. /// </summary> /// <returns></returns> public override DefinitionBase GetDefinition() return new NewsFieldDefinition(this); #region ICustomFieldDefinition Members [ConfigurationProperty(PropertyNames.Rows, DefaultValue = 1)] [ObjectInfo(typeof(ConfigDescriptions), Title = "RowsCaption", Description = "RowsDescription")] public int Rows get return(int)this[PropertyNames.Rows]; set this[PropertyNames.Rows] = value; [ConfigurationProperty(PropertyNames.HideIfValue)] [ObjectInfo(typeof(ConfigDescriptions), Title = "HideIfValueCaption", Description = "HideIfValueDescription")] public string HideIfValue get return(string)this[PropertyNames.HideIfValue]; set this[PropertyNames.HideIfValue] = value; [ConfigurationProperty(PropertyNames.ExpandableDefinition)] [ObjectInfo(typeof(ConfigDescriptions), Title = "ExpandableControlElementCaption", Description = "ExpandableControlElementDescription")] public new ExpandableControlElement ExpandableDefinitionConfig get return(ExpandableControlElement)this[PropertyNames.ExpandableDefinition]; set this[PropertyNames.ExpandableDefinition] = value; public IExpandableControlDefinition ExpandableDefinition get return this.ExpandableDefinitionConfig; internal struct PropertyNames public const string Rows = "rows"; public const string HideIfValue = "HideIfValue"; public const string ExpandableDefinition = "expandableDefinition"; #endregion #region IFieldDefinition members public override Type DefaultFieldType get return typeof(NewsField); #endregion #region IDefinition Members public new ConfigElement ConfigDefinition get throw new NotImplementedException(); #endregion
INewsFieldDefinition.cs
using System;using System.Collections.Generic;using System.Linq;using System.Web;using Telerik.Sitefinity.Web.UI.Fields.Contracts;using Telerik.Sitefinity.Web.UI.Extenders.Contracts;namespace Knowledgebase.Web.UI.Public interface INewsFieldDefinition : IFieldControlDefinition /// <summary> ///Gets or sets the number of rows displayed in a text box. /// </summary> /// <value>The rows.</value> int Rows get; set; /// <summary> /// Gets or sets the value which compared with the actual value of the Field, if equal hides the text. /// </summary> /// <value>The hide if value.</value> string HideIfValue get; set; IExpandableControlDefinition ExpandableDefinition get;
NewsFieldDefinition.cs
using System;using System.Collections.Generic;using System.Linq;using System.Web;using Telerik.Sitefinity.Configuration;using Telerik.Sitefinity.Web.UI.Fields.Definitions;using Telerik.Sitefinity.Web.UI.Fields.Contracts;using Telerik.Sitefinity.Web.UI.Extenders.Definitions;using Telerik.Sitefinity.Web.UI.Extenders.Contracts;namespace Knowledgebase.Web.UI.Public /// <summary> /// A control definition for the simple image field /// </summary> public class NewsFieldDefinition : FieldControlDefinition, INewsFieldDefinition #region Constuctors /// <summary> /// Initializes a new instance of the <see cref="NewsFieldDefinition"/> class. /// </summary> public NewsFieldDefinition() : base() /// <summary> /// Initializes a new instance of the <see cref="NewsFieldDefinition"/> class. /// </summary> /// <param name="element">The configuration element used to persist the control definition.</param> public NewsFieldDefinition(ConfigElement element) : base(element) #endregion #region Properties /// <value>The rows.</value> public int Rows get return this.ResolveProperty("Rows", this.rows); set this.rows = value; /// <summary> /// Gets or sets the value which compared with the actual value of the Field, if equal hides the text. /// </summary> /// <value>The hide if value.</value> public string HideIfValue get return this.ResolveProperty("HideIfValue", this.hideIfValue); set this.hideIfValue = value; /// <summary> /// Gets or sets the object that defines the expandable behavior of the hierarchical taxon field. /// </summary> /// <value></value> public IExpandableControlDefinition ExpandableDefinition get if(this.expandableDefinition == null) this.expandableDefinition = new ExpandableControlDefinition(); this.expandableDefinition.ControlDefinitionName = this.ControlDefinitionName; this.expandableDefinition.ViewName = this.ViewName; this.expandableDefinition.SectionName = this.SectionName; this.expandableDefinition.FieldName = this.FieldName; return this.expandableDefinition; set this.expandableDefinition = value; #endregion #region Private fields private IExpandableControlDefinition expandableDefinition; private int rows; private string hideIfValue; #endregion
NewsField.cs
using System;using System.Collections.Generic;using System.Linq;using System.Web.UI;using System.Web.UI.WebControls;using Telerik.Sitefinity.Web.UI;using Telerik.Sitefinity.Web.UI.Fields;using Telerik.Sitefinity.Web.UI.Fields.Enums;using Telerik.Web.UI;using Telerik.Sitefinity.Web.UI.Extenders;namespace Knowledgebase.Web.UI.Public /// <summary> /// A simple field control used to select news articles from the Database /// </summary> [FieldDefinitionElement(typeof(NewsFieldElement))] public class NewsField : FieldControl, IExpandableControl #region Properties /// <summary> /// Gets the name of the layout template. /// </summary> /// <value>The name of the layout template.</value> protected override string LayoutTemplateName get //return String.Empty; return "Knowledgebase.Web.UI.Public.NewsField.ascx"; /// <summary> /// Gets or sets the layout template path. /// </summary> /// <value>The layout template path.</value> /* public override string LayoutTemplatePath get return Page.ResolveClientUrl("~/Web/UI/Public/NewsSelector/NewsField.ascx"); set base.LayoutTemplatePath = value; */ /// <summary> /// Gets or sets the value. /// </summary> /// <value>The value.</value> public override object Value get var val = string.Empty; switch (this.DisplayMode) case FieldDisplayMode.Read: val = this.ImageControl.ImageUrl; break; case FieldDisplayMode.Write: val = "write"; //val = this.TextBoxControl.Text; break; return val; set if (this.ChildControlsCreated) switch (this.DisplayMode) case FieldDisplayMode.Write: //this.TextBoxControl.Text = value as string; break; case FieldDisplayMode.Read: this.ImageControl.ImageUrl = value as string; break; base.Value = null; else base.Value = value; /// <summary> /// Gets the label control. /// </summary> /// <value>The label control.</value> protected Label LabelControl get return this.Container.GetControl<Label>("textLabelRead", this.DisplayMode == FieldDisplayMode.Read); /// <summary> /// Gets the title label. /// </summary> /// <value>The title label.</value> protected Label TitleLabel get SitefinityLabel titleLabel = null; switch (this.DisplayMode) case FieldDisplayMode.Read: titleLabel = this.Container.GetControl<SitefinityLabel>("titleLabelRead", true); break; case FieldDisplayMode.Write: titleLabel = this.Container.GetControl<SitefinityLabel>("titleLabelWrite", true); break; return titleLabel; /// <summary> /// Gets the description label. /// </summary> /// <value>The description label.</value> protected Label DescriptionLabel get SitefinityLabel descriptionLabel = null; switch (this.DisplayMode) case FieldDisplayMode.Read: descriptionLabel = this.Container.GetControl<SitefinityLabel>("descriptionLabelRead", true); break; case FieldDisplayMode.Write: descriptionLabel = this.Container.GetControl<SitefinityLabel>("descriptionLabelWrite", true); break; return descriptionLabel; /// <summary> /// Gets the example label. /// </summary> /// <value>The example label.</value> protected Label ExampleLabel get SitefinityLabel exampleLabel = null; switch (this.DisplayMode) case FieldDisplayMode.Read: exampleLabel = this.Container.GetControl<SitefinityLabel>("exampleLabelRead", true); break; case FieldDisplayMode.Write: exampleLabel = this.Container.GetControl<SitefinityLabel>("exampleLabelWrite", true); break; return exampleLabel; /// <summary> /// Gets a reference to the <see cref="Image"/> control used to display the thumbnail in Read mode /// </summary> protected Image ImageControl get return this.Container.GetControl<Image>("image", this.DisplayMode == FieldDisplayMode.Read); /// <summary> /// Get a reference to the link that opens the simple image selector /// </summary> protected virtual HyperLink SelectLink get return this.Container.GetControl<HyperLink>("selectLink", this.DisplayMode == FieldDisplayMode.Write); /// <summary> /// Gets a reference to the RadWindowManager /// </summary> protected virtual RadWindowManager RadWindowManager get return this.Container.GetControl<RadWindowManager>("windowManager", true); #endregion protected override void InitializeControls(GenericContainer container) // this.ConstructControl(); #region IScriptControl Members /// <summary> /// Gets the script references. /// </summary> /// <returns></returns> public override IEnumerable<ScriptReference> GetScriptReferences() var baseReferences = new List<ScriptReference>(base.GetScriptReferences()); var newRef = new ScriptReference(newsFieldScript, this.GetType().Assembly.FullName); baseReferences.Add(newRef); return baseReferences; /// <summary> /// Gets the script descriptors. /// </summary> /// <returns></returns> public override IEnumerable<ScriptDescriptor> GetScriptDescriptors() var lastDescriptor = (ScriptControlDescriptor)base.GetScriptDescriptors().Last(); if (this.DisplayMode == FieldDisplayMode.Write) lastDescriptor.AddElementProperty("selectLink", this.SelectLink.ClientID); lastDescriptor.AddComponentProperty("windowManager", this.RadWindowManager.ClientID); if (this.DisplayMode == FieldDisplayMode.Read) lastDescriptor.AddElementProperty("imageControl", this.ImageControl.ClientID); yield return lastDescriptor; protected override WebControl TitleControl get return null; protected override WebControl ExampleControl get return null; protected override WebControl DescriptionControl get return null; public WebControl ExpandControl get return this.Container.GetControl<ConditionalTemplateContainer>("conditionalTemplate", true); public WebControl ExpandTarget get return this.Container.GetControl<ConditionalTemplateContainer>("conditionalTemplate", true); public bool? Expanded get return true; set //base.value = value; public string ExpandText get; set; #endregion #region Private Fields private const string newsFieldScript = "Knowledgebase.Web.UI.Public.NewsField.js"; #endregion
and finally, NewsField.ascx
<%@ Control Language="C#" AutoEventWireup="true" %><%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" TagPrefix="sitefinity" %><%@ Register Assembly="SitefinityWebApp" Namespace="Knowledgebase.Web.UI.Public" TagPrefix="kb" %><sitefinity:ResourceLinks ID="resourcesLinks" runat="server"> <sitefinity:ResourceFile JavaScriptLibrary="JQuery"> </sitefinity:ResourceFile></sitefinity:ResourceLinks><sitefinity:ConditionalTemplateContainer ID="conditionalTemplate" runat="server"> <Templates> <sitefinity:ConditionalTemplate Left="DisplayMode" Operator="Equal" Right="Read"> <sitefinity:SitefinityLabel id="titleLabelRead" runat="server" WrapperTagName="div" HideIfNoText="false" CssClass="sfTxtLbl"></sitefinity:SitefinityLabel> <sitefinity:SitefinityLabel id="textLabelRead" runat="server" WrapperTagName="div" HideIfNoText="false" CssClass="sfTxtContent"></sitefinity:SitefinityLabel> <asp:Image ID="image" runat="server" /> <sitefinity:SitefinityLabel id="descriptionLabelRead" runat="server" WrapperTagName="p" HideIfNoText="false" CssClass="sfDescription"></sitefinity:SitefinityLabel> <sitefinity:SitefinityLabel id="exampleLabelRead" runat="server" WrapperTagName="div" HideIfNoText="true" CssClass="sfExample" /> </sitefinity:ConditionalTemplate> <sitefinity:ConditionalTemplate Left="DisplayMode" Operator="Equal" Right="Write"> <sitefinity:SitefinityLabel ID="titleLabelWrite" runat="server" CssClass="sfTxtLbl" /> <asp:LinkButton ID="expandButton" runat="server" OnClientClick="return false;" CssClass="sfOptionalExpander" /> <asp:Panel ID="expandableTarget" runat="server" CssClass="sfFieldWrp"> <telerik:RadWindowManager ID="windowManager" runat="server" Skin="Sitefinity"> <Windows> <telerik:RadWindow ID="newsSelector" Width="600" Height="400" NavigateUrl="~/Sitefinity/Dialog/NewsSelectorDialog" runat="server" ReloadOnShow="true" Modal="true" VisibleStatusbar="false" Behaviors="Close" > </telerik:RadWindow> </Windows> </telerik:RadWindowManager> <asp:TextBox ID="textBox" runat="server" CssClass="sfTxt" /> <asp:HyperLink ID="selectLink" runat="server" NavigateUrl="javascript:void(0);" CssClass="sfLinkBtn sfChange"> <strong class="sfLinkBtnIn">Select...</strong> </asp:HyperLink> <sitefinity:SitefinityLabel id="descriptionLabelWrite" runat="server" WrapperTagName="div" HideIfNoText="true" CssClass="sfDescription" /> <sitefinity:SitefinityLabel id="exampleLabelWrite" runat="server" WrapperTagName="div" HideIfNoText="true" CssClass="sfExample" /> </asp:Panel> </sitefinity:ConditionalTemplate> </Templates></sitefinity:ConditionalTemplateContainer>
Sorry for all the code but the forums don't allow zip attachments.
Hello Chris,
Can you please make sure that your template is built as an embedded resource?
Regards,
Radoslav Georgiev
the Telerik team
Hi Radoslav,
Yes, I can confirm the ascx file is setup in the project as an embedded resource.
Chris
Hi Chris,
Can you please try using this path Knowledgebase.Web.UI.Public.NewsSelector.NewsField.ascx
Kind regards,
Radoslav Georgiev
the Telerik team