This post is on the older side and its content may be out of date.
Be sure to visit our blogs homepage for our latest news, updates and information.
There have been a lot of requests for a sample on Field Controls with a document selector, so I decided to show you how to make use of Sitefinity's EditorContentManagerDialog to select content inside field controls. This sample is simplified as much as it could be - there are no custom selectors, no hosting of dialogues inside windows - just the built-in EditorContentManagerDialog inside a field control.
The sample is built, using Slavo's ThumbnailSelectorField (for simplicity, the names inside have not been changed, so that it can be easier for you to make the connection between the two controls), so I won't be explaining in detail how field controls work, as this is already done by Slavo in his blog post.
In his sample, Slavo had a field control, an image selector and a dialogue. What I did was remove the selector and the dialogue and use only the field control. Inside, I put an EditorContentManagerDialog, which already has selectors inside, and even has different modes for selecting files/images, so it would be easy for you to transform this into an Image selector, as well.
Here's how I modified the template of the field control:
<%@ Control Language="C#" AutoEventWireup="true" %>
<%@ Register Assembly="Telerik.Sitefinity" Namespace="Telerik.Sitefinity.Web.UI" TagPrefix="sf" %>
<%@ Register Assembly="ThumbnailSelectorField" Namespace="Telerik.Sitefinity.Samples" TagPrefix="samples" %>
<
sf:ResourceLinks
ID
=
"resourcesLinks"
runat
=
"server"
>
<
sf:ResourceFile
JavaScriptLibrary
=
"JQuery"
>
</
sf:ResourceFile
>
</
sf:ResourceLinks
>
<
sf:ConditionalTemplateContainer
ID
=
"conditionalTemplate"
runat
=
"server"
>
<
Templates
>
<
sf:ConditionalTemplate
Left
=
"DisplayMode"
Operator
=
"Equal"
Right
=
"Read"
runat
=
"server"
>
<
sf:SitefinityLabel
id
=
"titleLabel_read"
runat
=
"server"
WrapperTagName
=
"div"
HideIfNoText
=
"false"
CssClass
=
"sfTxtLbl"
></
sf:SitefinityLabel
>
<
sf:SitefinityLabel
id
=
"textLabel_read"
runat
=
"server"
WrapperTagName
=
"div"
HideIfNoText
=
"false"
CssClass
=
"sfTxtContent"
></
sf:SitefinityLabel
>
<
sf:SitefinityHyperLink
id
=
"documentLink"
runat
=
"server"
/>
<
sf:SitefinityLabel
id
=
"descriptionLabel_read"
runat
=
"server"
WrapperTagName
=
"p"
HideIfNoText
=
"false"
CssClass
=
"sfDescription"
></
sf:SitefinityLabel
>
<
sf:SitefinityLabel
ID
=
"exampleLabel_read"
runat
=
"server"
WrapperTagName
=
"P"
HideIfNoText
=
"true"
CssClass
=
"sfExample"
/>
</
sf:ConditionalTemplate
>
<
sf:ConditionalTemplate
Left
=
"DisplayMode"
Operator
=
"Equal"
Right
=
"Write"
runat
=
"server"
>
<
sf:SitefinityLabel
ID
=
"titleLabel_write"
runat
=
"server"
CssClass
=
"sfTxtLbl"
/>
<
asp:LinkButton
ID
=
"expandButton_write"
runat
=
"server"
OnClientClick
=
"return false;"
CssClass
=
"sfOptionalExpander"
/>
<
asp:Panel
ID
=
"expandableTarget_write"
runat
=
"server"
CssClass
=
"sfFieldWrp"
>
<
sf:EditorContentManagerDialog
runat
=
"server"
ID
=
"asyncImageSelector"
DialogMode
=
"Document"
Width
=
"540"
HostedInRadWindow
=
"false"
BodyCssClass
=
""
/>
<
asp:TextBox
ID
=
"textBox_write"
runat
=
"server"
CssClass
=
"sfTxt"
/>
<
asp:LinkButton
ID
=
"replaceImage"
OnClientClick
=
"return false;"
runat
=
"server"
CssClass
=
"sfLinkBtn sfChange"
>
<
span
class
=
"sfLinkBtnIn"
><
asp:Literal
runat
=
"server"
ID
=
"AddImageLiteral"
Text
=
"Select..."
/></
span
>
</
asp:LinkButton
>
<
sf:SitefinityLabel
id
=
"descriptionLabel_write"
runat
=
"server"
WrapperTagName
=
"div"
HideIfNoText
=
"true"
CssClass
=
"sfDescription"
/>
<
sf:SitefinityLabel
id
=
"exampleLabel_write"
runat
=
"server"
WrapperTagName
=
"div"
HideIfNoText
=
"true"
CssClass
=
"sfExample"
/>
</
asp:Panel
>
</
sf:ConditionalTemplate
>
</
Templates
>
</
sf:ConditionalTemplateContainer
>
As you can see I replaced the <img> control in Read Mode with a Sitefinity Hyperlink,which will be used as a link to the document and I also replaced the Rad WindowManager with the EditorContentManagerDialog.
Then in the codefile of my field, I added references to the new control, removed the old ones and changed the way Documents are displayed in Read mode:
public
override
object
Value
{
get
{
var val =
string
.Empty;
switch
(
this
.DisplayMode)
{
case
FieldDisplayMode.Read:
val =
this
.DocumentLink.NavigateUrl;
break
;
case
FieldDisplayMode.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:
var imageId =
new
Guid(value.ToString());
var document = App.WorkWith().Document(imageId).Get();
this
.DocumentLink.NavigateUrl = document.Url;
this
.DocumentLink.Text = document.Title;
break
;
}
base
.Value =
null
;
}
else
{
base
.Value = value;
}
}
}
protected
EditorContentManagerDialog AsyncImageSelector
{
get
{
return
this
.Container.GetControl<EditorContentManagerDialog>(
"asyncImageSelector"
,
false
);
}
}
and I also added the dialog to the ScriptDescriptors, so I can have a reference object of it inside the client component:
public
override
IEnumerable<ScriptDescriptor> GetScriptDescriptors()
{
var lastDescriptor = (ScriptControlDescriptor)
base
.GetScriptDescriptors().Last();
if
(
this
.DisplayMode == FieldDisplayMode.Write)
{
lastDescriptor.AddElementProperty(
"replaceImageButtonElement"
,
this
.ReplaceImageButton.ClientID);
lastDescriptor.AddComponentProperty(
"asyncImageSelector"
,
this
.AsyncImageSelector.ClientID);
}
if
(
this
.DisplayMode == FieldDisplayMode.Read)
{
lastDescriptor.AddElementProperty(
"imageControl"
,
this
.DocumentLink.ClientID);
}
yield
return
lastDescriptor;
}
Finally, I modified the javascript part of the field to get the selected item from the dialog and set its ID as a Value of the field control:
On initialize I create all the needed handlers and delegates (and then remove them on dispose):
initialize:
function
() {
Telerik.Sitefinity.Samples.SimpleImageField.callBaseMethod(
this
,
"initialize"
);
this
._replaceImageButtonElementClickDelegate = Function.createDelegate(
this
,
this
._replaceImageButtonElementClicked);
if
(
this
._replaceImageButtonElement) {
$addHandler(
this
._replaceImageButtonElement,
"click"
,
this
._replaceImageButtonElementClickDelegate);
}
this
._onLoadDelegate = Function.createDelegate(
this
,
this
._onLoad);
Sys.Application.add_load(
this
._onLoadDelegate);
this
._onUnloadDelegate = Function.createDelegate(
this
,
this
._onUnload);
Sys.Application.add_unload(
this
._onUnloadDelegate);
if
(
this
._asyncImageSelector) {
this
._uploadDialog = jQuery(
this
._asyncImageSelector.get_element()).dialog({
autoOpen:
false
,
modal:
true
,
width: 540,
height:
"auto"
,
closeOnEscape:
true
,
resizable:
false
,
draggable:
false
,
zIndex: 5000,
dialogClass:
"sfSelectorDialog"
});
this
._asyncImageSelectorInsertDelegate = Function.createDelegate(
this
,
this
._asyncImageSelectorInsertHandler);
this
._asyncImageSelector.set_customInsertDelegate(
this
._asyncImageSelectorInsertDelegate);
}
},
The tree delegates are for opening the dialogue on button click (replaceImageButtonElementClicked), setting the Read mode value (_set_readModeValue) and setting the selected item's ID to the value of the field on the dialogue's item selected event (_asyncImageSelectorInsertHandler).
replaceImageButtonElementClicked:
function
(sender, args) {
this
._uploadDialog.dialog(
"open"
);
var
scrollTopHtml = jQuery(
"html"
).eq(0).scrollTop();
var
scrollTopBody = jQuery(
"body"
).eq(0).scrollTop();
var
scrollTop = ((scrollTopHtml > scrollTopBody) ? scrollTopHtml : scrollTopBody) + 50;
jQuery(
this
._uploadDialog).parent().css({
"top"
: scrollTop });
try
{
this
._asyncImageSelector.get_uploaderView().get_altTextField().set_value(
""
);
}
catch
(ex) { }
jQuery(
this
._asyncImageSelector.get_uploaderView().get_settingsPanel()).hide();
return
false
;
},
/* -------------------- private methods ----------- */
_set_readModeValue:
function
(value) {
if
(value === undefined || value ==
null
) {
this
._clearLabel();
}
},
_asyncImageSelectorInsertHandler:
function
(selectedItem) {
if
(selectedItem) {
this
.set_value(selectedItem.Id);
this
._uploadDialog.dialog(
"close"
);
}
},
Installation instructions (basically they are almost the same as in Slavo's post):
1) Extract the files into a folder
2) Add them as an external project to your Sitefinity solution
3) Copy/paste the global.asax file into SitefinityWebApp (or if you already have an existing one, add the code to it) or manually register a virtual path ~/ThumbnailSelector/* (this is used for the template of the control). It can be done from the Backend -> Administration >> Settings >> Advanced >> VirtualPathSettings.
4) Set the build action for the .ascx and .js files to EmbeddedResource
5) Add a reference to the control's project in SitefinityWebApp
6) Add the .js file as a web resource in AssemblyInfo.cs of SitefinityWebApp:
[assembly: WebResource(
"SitefinityWebApp.SimpleImageField.SimpleImageField.js"
,
"application/x-javascript"
)]
7) Compile and run your project
8) Create a custom field in any module (works for ECommerce, as well) and specify a custom widget for entering data. The type of the custom widget should be Telerik.Sitefinity.Samples.SimpleImageField
9) For read mode, you can add the SimpleImageField in your content-widget templates like this (assuming the field is called Thumbnail):
<
samples:SimpleImageField
runat
=
"server"
DisplayMode
=
"Read"
Value='<%# Eval("Thumbnail")%>' />
Subscribe to get all the news, info and tutorials you need to build better business apps and sites