The content you're reading is getting on in years
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.
[This post is part of the developer's manual preview published on this blog. You can find temporary TOC here.]
View is a main building unit of the new Sitefinity backend architecture. If you need to refresh your memory you can take a look at Architecture overview article to get a broader understanding of the Views and their place in Sitefinity.
Views can be created from composite controls or user controls, by deriving from ViewModeControl<T> and ViewModeUserControl<T> base classes respectively. Let us start by constructing a simple View and walk our way backwards from the samples to the concepts.
SAMPLE 1: Creating a view with custom control
using System; |
using Telerik.Cms.Web.UI; |
/// <summary> |
/// ContactsView of the Contacts module |
/// </summary> |
public class ContactsView : ViewModeControl<ContactsControlPanel> |
{ |
} |
SAMPLE 2: Creating a view with user control
using System; |
using Telerik.Cms.Web.UI; |
public partial class Sample1_ContactsEditView : ViewModeUserControl<ContactsView> |
{ |
protected void Page_Load(object sender, EventArgs e) |
{ |
} |
} |
As you can see all you need to do in order to create a new View is to create a new class and inherit from ViewModeControl or ViewModeUserControl in which case we will create a new user control.
As it becomes apparent now, ViewModeControl and ViewModeUserControl classes are generic and we need to specify generic argument when inheriting from them. The argument we are specifying here is the host of the View. You can think of host as a parent view, the view to which this view is a subview.
We see that in Sample 1, host view is ContactsControlPanel View, while in the Sample 2, host or parent is ContactsView View.
*** BEGIN NOTE ***
You may have read that Views should be host ambivalent, meaning that they could be plugged anywhere in the hierarchy of views. Views in Sample 1 and Sample 2 are not host ambivalent. View in Sample 1 always needs to be hosted by View of type ContactsControlPanel, while View in Sample 2 must always be hosted by View of type ContactsView.
To make View host ambivalent we can define it as follows:
SAMPLE 3: Creating host ambivalent views
using System; |
using Telerik.Cms.Web.UI; |
/// <summary> |
/// ContactsView of the Contacts module |
/// </summary> |
public class ContactsView<THost> : ViewModeControl<THost> where THost : Control |
{ |
} |
By taking this approach, we have enabled our View to be hosted by any class that inherits from Control class, and in effect this means by any other ViewModeControl or ViewModeUserControl classes. We have made our View host ambivalent.
Sometimes it makes sense to design Views that can be hosted by only particular type of a View (e.g. CommentsEdit must be hosted by CommentsView), while sometimes it is better to make host ambivalent Views (e.g. CommentsView should be able to work with different types of Views, so that we can reuse it in Control Panel classes for News, Events, Blogs and so on).
*** END NOTE ***
using Telerik.Cms.Web.UI; |
/// <summary> |
/// MyView View |
/// </summary> |
public class MyView : ViewModeControl<ContactsControlPanel> |
{ |
/// <summary> |
/// Gets or sets the layout template path of the View |
/// </summary> |
public override string LayoutTemplatePath |
{ |
get |
{ |
if(string.IsNullOrEmpty(this.layoutTemplatePath)) |
this.layoutTemplatePath = "~/Sample3/MyViewTemplate.ascx"; |
return this.layoutTemplatePath; |
} |
set |
{ |
this.layoutTemplatePath = value; |
} |
} |
private string layoutTemplatePath; |
} |
So as you can see, all you need to do in order to instantiate a template in a view is to override the LayoutTemplatePath property and ViewModeControl will do the rest of work for you (including adding the controls).
If your views are not part of the website, but rather a class library you may want to embed your templates together with the project. Embedding templates is really simple just as is instantiating user interface from them. To embed your template within a class library, you need to copy the file to the project and set it’s Build Action to “Embedded Resources.
SAMPLE 5: Instantiating embedded template in a View
using System.Web.UI; |
using Telerik.Cms.Web.UI; |
namespace ViewSamples |
{ |
/// <summary> |
/// MyView View |
/// </summary> |
public class MyProjectView<THost> : ViewModeControl<THost> where THost : Control |
{ |
protected override string LayoutTemplateName |
{ |
get |
{ |
return MyProjectViewTemplateName; |
} |
} |
private const string MyProjectViewTemplateName = |
"ViewSamples.Resources.ControlTemplates.Backend.MyViewTemplate.ascx"; |
} |
} |
This time we are overriding LayoutTemplateName property and simply returning the name of resource which holds our embedded template.
*** BEGIN NOTE ***
ViewModeControl classes have a built in system for mapping your embedded templates to an external one, so you do not need to worry about that. More on this subject in articles about the ControlConfig configuration file.
*** END NOTE ***
We can also add controls programmatically to our Views and to do so we need to override the InitializeControls method:
*** BEGIN WARNING ***
Do not override CreateChildControls method directly. For the purposes of your development use InitializeControls which will be called at the opportune time for your controls to be initialized.
*** END WARNING ***
SAMPLE 6: Adding controls programmatically to the collection of child controls
using System.Web.UI; |
using Telerik.Cms.Web.UI; |
using System.Web.UI.WebControls; |
namespace ViewSamples |
{ |
/// <summary> |
/// MyView View |
/// </summary> |
public class MyProjectView<THost> : ViewModeControl<THost> where THost : Control |
{ |
protected override void InitializeControls(Control viewContainer) |
{ |
Label testLabel = new Label(); |
testLabel.Text = "Test label!"; |
this.Controls.Add(testLabel); |
} |
} |
} |
The neat thing about the new architecture is that ViewModeControl base class is taking care of all this plumbing for you. Let us see how all this works with the new architecture.
SAMPLE 7: Accessing controls defined in templates
using System.Web.UI; |
using Telerik.Cms.Web.UI; |
using System.Web.UI.WebControls; |
namespace ViewSamples |
{ |
/// <summary> |
/// MyView View |
/// </summary> |
public class MyProjectView<THost> : ViewModeControl<THost> where THost : Control |
{ |
protected override string LayoutTemplateName |
{ |
get |
{ |
return MyProjectViewTemplateName; |
} |
} |
protected virtual IButtonControl MyViewButton |
{ |
get |
{ |
return base.Container.GetControl<IButtonControl>("myViewButton", true); |
} |
} |
protected override void InitializeControls(System.Web.UI.Control viewContainer) |
{ |
MyViewButton.Text = "I have been changed!"; |
} |
private const string MyProjectViewTemplateName = |
"ViewSamples.Resources.ControlTemplates.Backend.MyViewTemplate.ascx"; |
} |
} |
There are several important things in the sample above. Notice that we have overridden InitializeControls method and changed the text property of the MyViewButton property. Then we take a look and see how have we implemented MyViewButton property. All we did is called GetControl function of the Container object (that has been initialized with template for us on the base class) and specified what type of control we are looking for, specified the ID of the control that we wish to return and finally set true for the isRequiredControl argument.
ViewModeControl base class will do everything else for us.
Another important thing to note here is that MyViewButton is a virtual property of our view. Since we have specified to GetControl function that control is required an exception will be thrown if the control is not present in the template. Let us suppose now that we want to reuse this view, but we don’t need the MyViewButton control anymore. We have the ability to simply override MyViewButton property in our derived class as follows:
SAMPLE 8: Changing the control requirement
protected override IButtonControl MyViewButton |
{ |
get |
{ |
return base.Container.GetControl<IButtonControl>("myViewButton", false); |
} |
} |
Alternatively, we could return just null.
SAMPLE 9: Adding Subviews to a View
using Telerik.Cms.Web.UI.Backend; |
/// <summary> |
/// ContactsControlPanel root view class |
/// </summary> |
public class ContactsControlPanel : ControlPanel<ContactsControlPanel> |
{ |
/// <summary> |
/// We add the views to the control panel. The two views we are adding are so called "container" views, since |
/// they do not have user interface and display their default child view. |
/// </summary> |
protected override void CreateViews() |
{ |
AddView<ContactsView>("Contacts", "Contacts", "From here you can manage all the contacts.", "all", null); |
AddView<DepartmentsView>("Departments", "Departments", "From here you can manage all the departments", "all", null); |
} |
} |
SAMPLE 10: Adding Subviews based on User Controls to a View
using Telerik.Cms.Web.UI; |
/// <summary> |
/// Summary description for ContactsView |
/// </summary> |
public class ContactsView : ViewModeControl<ContactsControlPanel> |
{ |
/// <summary> |
/// Creates the child views for the contacts view |
/// </summary> |
protected override void CreateViews() |
{ |
AddView("ContactsListView", "~/Sample1/ContactsListView.ascx", "Contacts List", "List of all contacts", string.Empty, null); |
AddView("ContactsInsertView", "~/Sample1/ContactsInsertView.ascx", "Contacts Insert", "Inserts new contact", string.Empty, null); |
AddView("ContactsEditView", "~/Sample1/ContactsEditView.ascx", "Contacts Edit", "Edits contact", string.Empty, null); |
AddView("ContactsPreviewView", "~/Sample1/ContactsPreviewView.ascx", "Preview Contact", "Previews the contact", string.Empty, null); |
} |
} |
The difference is pretty much what you would expect. We do not specify the generic type of the view, but rather we have another argument where we specify the virtual path of the user control which implements the view.
View all posts from The Progress Team on the Progress blog. Connect with us about all things application development and deployment, data integration and digital business.
Let our experts teach you how to use Sitefinity's best-in-class features to deliver compelling digital experiences.
Learn MoreSubscribe to get all the news, info and tutorials you need to build better business apps and sites
Progress collects the Personal Information set out in our Privacy Policy and the Supplemental Privacy notice for residents of California and other US States and uses it for the purposes stated in that policy.
You can also ask us not to share your Personal Information to third parties here: Do Not Sell or Share My Info
We see that you have already chosen to receive marketing materials from us. If you wish to change this at any time you may do so by clicking here.
Thank you for your continued interest in Progress. Based on either your previous activity on our websites or our ongoing relationship, we will keep you updated on our products, solutions, services, company news and events. If you decide that you want to be removed from our mailing lists at any time, you can change your contact preferences by clicking here.