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);
#endregion
Hello 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