+1-888-365-2779
Try Now
More in this section
Categories
Bloggers
Blogs RSS feed

Sitefinity 3.6 new backend architecture - What are Views?

by Ivan Osmak

[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 ***

Instantiating controls in Views


Generally speaking, when creating Views you should have a template for the View which will define the user interface of the View. While this is not a requirement (you can add controls programmatically) it is recommended, since you will decouple the actual ASP.NET markup and your View logic.

SAMPLE 4: Instantiating template in the view

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); 
        } 
    } 
 

Accessing controls inside of the templates


Seasoned Sitefinity users may recall that prior to Sitefinity 3.6 we would declare a GenericContainer<T> type of object on a class and then implement the properties for accessing the controls inside of the templates. Sitefinity 3.6 introduces a slight change of thinking here, though the principle is still the same. Instead of GenericContainer<T> class, a new class has been implemented named GenericContainer together with several overloads of GetControl<T> function, which replaces obsolete FindRequiredControl and FindOptionalControl functions.

 

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.

 

Adding Subviews to the View


So far we have put a lot of accent on the hierarchy of Views and its benefits. To add Subviews to a View all we need to do is override CreateViews() method and call one of the override of the base method AddView.

 

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); 
    } 
 

There are several overloads of the AddView method; depending on your scenario you will choose the most appropriate.  In the Sample 8, we have added two views based on ViewModeControl and then specified following arguments:
  • ViewName - the name by which view will be distinguished from other views
  • ViewTitle - title will be used if you are using automatic command generation as the title of the command, as well as the title of the automatic breadcrumb
  • ViewDescription - description will be used for the description of the command if you use automatic command generation
  • ViewCommandCssClass - css class of the command if you use automatic command generation
  • ResourcesManager - if you specify ResourcesManager, then ViewTitle and ViewDescription will become keys of the localization file and allow you to have localized commands even if you are using automatic command generation
At the end of this topic, when we explain base classes in the more detail, we will provide exhaustive explanations of each of the overloads. For now, we’ll only take a look at one more sample, namely we’ll demonstrate how to add Views that are based on ViewModeUserControl class (views that are created from user controls and not custom controls).

 

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.

 

Conclusion


In this article we have learned what views are and how to achieve most common tasks with Views. Now, that we have seen the samples, let us derive some conclusions about views.
  • Views are building units of the modules in the new Sitefinity backend architecture
  • Views can be created from composite controls (which inherit from ViewModeControl base class) or user controls (which inherit from ViewModeUserControl base class).
  • Depending on our design intentions, Views can be host ambivalent or host specific
  • Views are only controls, allowing them to have child controls
  • Views can have Subviews, thus creating hierarchy
  • Views have built in support for templates and retrieval of controls defined in templates.
  • Views have built in support for working with external templates, embedded templates or templates defined in the ControlsConfig configuration file
  • Views can have only one template and should have single responsibility
Now that we have got a pretty good grasp of a View as an individual building unit, in the next article we will start exploring Views as a part of hierarchy. As a first order of business, we will learn how to navigate between Views.

Leave a comment