In the example below, you will learn how to extend system objects with your own fields or data.
This extending is possible thanks to the IRelatedData interface and the RelatedData (object) property. If an object implements the IRelatedData interface, you can use its RelatedData (object) property to connect just any object to it. The connected object is then shipped as a part of the system object.
On the top of it, you can also make the related object behave as a native part of the system object and retrieve its properties as if it were properties of the system object. If the connected object implements the IDataContainer interface, it gets automatically connected to the system object's GetValue and SetValue methods.
Example
Let's presume that you want to customize the SiteInfo object with two additional properties and one method:
• | SiteOwner - String, just the name of the site owner |
• | SiteValidUntil - DateTime until which the site is valid |
• | bool IsValid() - Returns true if the site is valid at the current time |
1. First, you will need to create a custom class in the solution, containing the properties and the method as you can see in the code example below:
SiteRegistration.cs
using System; using CMS.SettingsProvider;
/// <summary> /// Summary description for SiteRegistration /// </summary> public class SiteRegistration : IDataContainer { #region "Variables"
private string mSiteOwner = null; private DateTime mSiteValidUntil = DateTime.MinValue;
#endregion
#region "Properties"
/// <summary> /// Gets or sets the site owner /// </summary> public string SiteOwner { get { return mSiteOwner; } set { mSiteOwner = value; } }
/// <summary> /// Gets or sets the date until which the site is valid /// </summary> public DateTime SiteValidUntil { get { return mSiteValidUntil; } set { mSiteValidUntil = value; } }
#endregion
#region "IDataContainer members"
/// <summary> /// Gets the column names /// </summary> public string[] ColumnNames { get { return new string[] { "SiteOwner", "SiteValidUntil" }; } }
/// <summary> /// Returns true /// </summary> /// <param name="columnName"></param> public bool ContainsColumn(string columnName) { switch (columnName.ToLower()) { case "siteowner": case "sitevaliduntil": return true;
default: return false; } }
/// <summary> /// Gets the object value /// </summary> /// <param name="columnName">Column name</param> public object GetValue(string columnName) { switch (columnName.ToLower()) { case "siteowner": return mSiteOwner;
case "sitevaliduntil": return mSiteValidUntil;
default: return null; } }
/// <summary> /// Sets the field value /// </summary> /// <param name="columnName">Column name</param> /// <param name="value">New value</param> public bool SetValue(string columnName, object value) { switch (columnName.ToLower()) { case "siteowner": mSiteOwner = (string)value; return true;
case "sitevaliduntil": mSiteValidUntil = (DateTime)value; return true;
default: return false; } }
/// <summary> /// Tries to get the value from the object /// </summary> /// <param name="columnName">Column name</param> /// <param name="value">Returns the value</param> public bool TryGetValue(string columnName, out object value) { switch (columnName.ToLower()) { case "siteowner": value = mSiteOwner; return true;
case "sitevaliduntil": value = mSiteValidUntil; return true;
default: value = null; return false; } }
#endregion
#region "Methods"
/// <summary> /// Returns true if the site is valid /// </summary> public bool IsValid() { return this.SiteValidUntil > DateTime.Now; }
#endregion } |
2. Now that you have the class ready, you will want to bind it to the SiteInfo object. The binding will be dynamic, which means that the data will be loaded when it is requested. We will use the OnLoadRelatedData event which you can use for specific object types, including our SiteInfo objects. The event is part of the type information object referenced from the object info class.
What you need to do is to create the event and register it in the AfterApplicationStart event, both in the ~/App_Code/Global/CMS/CMSApplication.cs class as you can see below:
[C#]
/// /// Fires after the application start event /// public static void AfterApplicationStart(object sender, EventArgs e) { // Add your custom actions CMS.SiteProvider.SiteInfo.TYPEINFO.OnLoadRelatedData += new CMS.SettingsProvider.TypeInfo.ObjectLoadRelatedDataEventHandler(SiteInfo_OnLoadRelatedData); }
static object SiteInfo_OnLoadRelatedData(CMS.SettingsProvider.IInfoObject infoObj) { // Get the related data from your external storage (make sure it implements IDataContainer. Here are just some data created on-the-fly. SiteRegistration sr = new SiteRegistration(); sr.SiteOwner = "Martin Hejtmanek"; sr.SiteValidUntil = DateTime.Now.AddDays(1);
return sr; } |
3. Now try to paste the following code to the layout of some page on your site. Notice the bold parts of the code. As you can see, data stored in the custom properties are retrieved using the GetValue method as if they were a native part of the SiteInfo object.
<asp:Label runat="server" id="lblSiteInfo" /> <script runat="server"> protected void Page_PreRender(object sender, EventArgs e) { CMS.SiteProvider.SiteInfo currentSite = CMSContext.CurrentSite;
this.lblSiteInfo.Text = String.Format("Site '{0}' is valid until {1} and owned by {2}.", currentSite.DisplayName, currentSite.GetValue("SiteValidUntil"), currentSite.GetValue("SiteOwner")); } </script> |
As a result, you should see the following text on the page:
Site 'Corporate Site' is valid until 9/15/2009 1:09:50 PM and owned by Martin Hejtmanek.
4. It is also possible to get the values of the custom properties using macros. Try adding the Text -> Static text web part to your page and paste the following text to its Text property. The same text as in the previous example should be displayed on the live site.
Site '{%CMSContext.CurrentSite.SiteDisplayName%}' valid until {%CMSContext.CurrentSite.SiteValidUntil%} and owned by {%CMSContext.CurrentSite.SiteOwner%} |