EPiServer : Dynamic Data Store

If you are reading this post, then I can assume you are curios about EPiServer dynamic data store and want to know how to use it. In this post, I am going to do exactly the same. I will create, update and delete from DDS using EPiServer API.

1- Create a new dynamic data store

Imagine you have to dynamically store landing page ids for certain products or sections and then read them back from dynamic data store

private void CreateLandingPageDDS(PageData myPage)
{
//create a propertybag
PropertyBag landingProperties = new PropertyBag();

//add your custom properties
landingProperties.Add("LandingPageKey", myPage.PageLink.ID.ToString());
landingProperties.Add("LandingPageProductName", myPage.PageName);
//add more properties if you like, but there is a limit that you can add upto, or
//create a custom object and add that object

//create a new store for DDS
DynamicDataStore store = DynamicDataStoreFactory.Instance.CreateStore("DDS",   landingProperties.GenerateTypeBag());

//store DDS in database
Identity id = store.Save(landingProperties);

}

pretty simple 🙂

2- Get dynamic data store

Now let say you want to query the same DDS and would like to get pageName if you pass in the pageID

public static string GetLandingPageName(string currentPageID)
{
//get the store from database
DynamicDataStore store = (DynamicDataStore)DynamicDataStoreFactory.Instance.GetStore("DDS");

if (store != null)
{
//find all the properties for that key/value pair
IEnumerable<PropertyBag> landingProperties = store.FindAsPropertyBag("LandingPageKey", currentPageID);

//iterate through each property and return only where key matches
if (landingProperties != null)
{
foreach (PropertyBag item in landingProperties)
{
string pageName = item["LandingPageProductName"] as string ?? string.Empty;
return pageName;
}

}

}
return string.Empty;
}

Although pageName is a trivial property, this is just an example how to go about using DDS.

3- Update dynamic data store

Now let say you want to update pageName using pageID

private void UpdateLandingPage(string currentPageID)
{
DynamicDataStore store = (DynamicDataStore)DynamicDataStoreFactory.Instance.GetStore("DDS");

if (store != null)
{
IEnumerable<PropertyBag> landingProperties = store.FindAsPropertyBag("LandingPageKey", currentPageID);

if (landingProperties != null)
{
foreach (PropertyBag item in landingProperties)
{
item["LandingPageProductName"] = "New name";
store.Save(item);
}


}

}
}

4- Delete dynamic data store

That is very strait forward, just use

DynamicDataStoreFactory.Instance.DeleteStore("DDS",true);

5-Important note

If during development, you have to change your dynamic data store by adding more properties to property bag object, it will result in exception.

There are two ways to get round this

1.If you are in development, delete your previous DDS entries and start fresh
2.If you are in production, then you have to re-map/re-link the property bag.

Have fun coding DDS

EPiServer : CustomProperty for Radio Button List

EPiServer has lots of in-built properties, but one major property that it is missing is ‘radio button list’ , sometimes user wants to select just one option from give 4 or 5 options.

In this post, I will guide you through making a very basic custom property for EPiServer for ‘Radio Button List’

Step1: In your VS project, right-click and new EPiServer custom property control as show below, i will rename this control is ‘PropertyMyPicker’

Add custom property
Add custom property

Step2: Inherit it from ‘PropertyString’ as shown below

Inherit from property string
Inherit from property string

Step3: This will create two code files in your project as following

PropertyMyPicker.cs

PropertyMyPickerControl.cs

You do not need to do anything in ‘PropertyMyPicker.cs’ class, and all your logic will be implemented in  ‘PropertyMyPickerControl.cs’.

Step4: In this code snippet,  we create 3 radio buttons, if their value is selected, that text is stored in the database and when the page is re-visited/re-loaded the value is read back from the database. Change the code of the ‘PropertyMyPickerControl.cs’ as shown below and make necessary namespace and variable changes. You have overwrite some of the methods and implement your own if necessary.

/// <summary>
/// PropertyControl implementation used for rendering PropertyMyPicker data.
/// </summary>
public class PropertyMyPickerControl : EPiServer.Web.PropertyControls.PropertyStringControl
{
RadioButton radioButton1 = null;
RadioButton radioButton2 = null;
RadioButton radioButton3 = null;
// Value that will be stored in db,
string desc = string.Empty;
// group name for all radio buttons to make them behave as radiobuttonlist
readonly string groupName = "MyPicker";
/// <summary>
/// Gets the PropertyMyPicker instance for this IPropertyControl.
/// </summary>
/// <value>The property that is to be displayed or edited.</value>
public PropertyMyPicker PropertyMyPicker
{
get
{
return PropertyData as PropertyMyPicker;
}
}
/// <summary>
///creates radio button list and pre-select if the value
///has been saved in database
/// </summary>
public override void CreateEditControls()
{
//add radioButton1 radio button
radioButton1 = new RadioButton();
radioButton1.Text = "Radio 1 Text";
radioButton1.GroupName = groupName;
radioButton1.Checked = IsRadioChecked(radioButton1.Text);
//add radioButton2 radio button
radioButton2 = new RadioButton();
radioButton2.Text = "Radio 2 Text"
radioButton2.GroupName = groupName;
radioButton2.Checked = IsRadioChecked(radioButton2.Text);
//add radioButton3 radio button
radioButton3 = new RadioButton();
radioButton3.Text = "Radio 3 Text";
radioButton3.GroupName = groupName;
radioButton3.Checked = IsRadioChecked(radioButton3.Text);

this.Controls.Add(radioButton1);
this.Controls.Add(radioButton2);
this.Controls.Add(radioButton3);

}
/// <summary>
/// Saves it to the database
/// </summary>
public override void ApplyEditChanges()
{
desc = GetMyDescription();
base.SetValue(desc);
}
/// <summary>
/// Get selected radio button text
/// </summary>
/// <returns></returns>
private string GetMyDescription()
{
string selectedMyPicker = string.Empty;

if (radioButton1.Checked)
selectedMyPicker = "Radio 1 Text";
else if (radioButton2.Checked)
selectedMyPicker = "Radio 2 Text";
else if (radioButton3.Checked)
selectedMyPicker ="Radio 3 Text";

return selectedMy;

}
/// <summary>
/// Check if the controls contain value for any of the radio button in database
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
private bool IsRadioChecked(string name)
{
if (this.PropertyData.Value != null)
{
string selectedMy = this.PropertyData.Value.ToString();
if (selectedMy.ToLower() == name.ToLower())
return true;
}
return false;
}

}

Step 5: Next you need to create the property for the page template, you will see your new property in the dropdown list

Step 6: You can use this property as a page string property and output your custom logic

//assuming MyPicker is the page property name
var myPicker = CurrentPage["MyPicker"] as string;

if (!String.IsNullOrEmpty(myPicker))
{
  //add your custom logic here
}

Thats it, job done!

Sitecore : Extending OnItemSave Handler

In a recent project, I have to update certain fields of sitecore item when the item is saved in sitecore.

The solution I went for involved extending item:saved event and adding my own handler to do certain actions based upon template type

If you are in a similar situation, here are the steps to do

1. Create you custom class with a public method to perform your logic
2. In web.config under <events> find , <event name=”item:saved”> and append your handler at the end.

Here is basic class code

public class ItemSaveEventHandler
{
//master database name
public static readonly string Master = "master";
//sample template id
public static readonly string TemplateIdItem = "{67B44133-70CD-405C-BDAF-B93E5AEA2682}";

public void OnItemSaved(object sender, EventArgs args)
{

Item temp = Event.ExtractParameter(args, 0) as Item;
//make sure you are in edit mode and not in publish mode
if (temp != null && temp.Database.Name.ToLower() == Master)
{
//check if the template is what you are looking for
if (temp.TemplateID.ToString() == TemplateIdItem )
{
//do your stuff with the item, this is just a sample
temp.Editing.BeginEdit();
temp.Fields["Title"] = "new item saved title";
temp.Editing.EndEdit();
temp.Editing.AcceptChanges();

}

}

}

Complie and debug code, when you are ready change the web.config

<event name="item:saved">
<handler type="Sitecore.Links.ItemEventHandler, Sitecore.Kernel" method="OnItemSaved"/>
<handler type="Sitecore.Globalization.ItemEventHandler, Sitecore.Kernel" method="OnItemSaved"/>
<handler type="Sitecore.Rules.ItemEventHandler, Sitecore.Kernel" method="OnItemSaved"/>
<!-- add the namespace name and assembly dll name as per your site -->
<handler type="<MyWebsite.Handlers.ItemSaveEventHandler>, <MyWebsite.Hanlders>" method="OnItemSaved"/>
</event>

Thats it, if everything is correct the event handler will be called when someone saves an item in sitecore

Cheers

Sitecore : Adding schedule jobs via agents

This is a really short and sweet post. Sometimes you have to add scheduled jobs to query sitecore items at regular intervals and perform some custom logic.

The easiest way to do it is by adding your code as an agent to the web.config and setting up the interval

First, create your custom class, this could either be within the main website or a separate class library project something like

namespace  Website.AgentsNamespace
{
public class MyAgentClass
{
   public static void Run()
   {
     //add your custom logic here
     //call sitecore, services, database whatever
     //its up to you

   }
}
}

Compile and make sure there are no bugs.

Navigate to web.config and find

<scheduling>

node. Add your class as an agent and set the time interval like

<agent type="[name.of.your.class.including.namespace], [name.of.dll.where.the.class.is.compiled]" method="Run" interval="00:05:00" />

Thats it, job done.

Check the logs, and see when sitecor adds the job to scheduler.

Repeater OnItemCommand

In this post I will show a simple implementation on OnItemCommand of the repeater control.

This is suitable when you render items in a repeater and want to edit individual items

Consider this sample class

public class Products

{
public string ProductCode {get;set;}
public string ProductName {get;set;}
public decimal ProductPrice {get;set;}

}

You can display objects from this class very easily using any database call or Linq

In your repeater, you have a button to ‘Edit’ next to each product, which will allow admin users to change prices

So, the repeater might looks like this

 <asp:Repeater ID="RepeaterListOfProducts" runat="server" OnItemDataBound="RepeaterListOfProducts_OnItemDataBound" OnItemCommand="RepeaterListOfProducts_OnItemCommand">

<HeaderTemplate><ul></HeaderTemplate>

<ItemTemplate>

<li>
<label>

       <asp:Literal ID="LiteralProdcutCode" runat="server"></asp:Literal>
        <asp:Literal ID="LiteralProdcutName" runat="server"></asp:Literal>
        <asp:Literal ID="LiteralProductPrice" runat="server" ></asp:Literal>
</label>
        <asp:Button ID="ButtonEditProduct" runat="server" Text="Edit" CommandName="Edit" />

</li>

</ItemTemplate>

<FooterTemplate></ul></FooterTemplate>

</asp:Repeater>

In code behind, you have a function to populate products something like

RepeaterListOfProducts.DataSource = db.GetAllProducts();
RepeaterListOfProducts.DataBind();

In OnItemDataBound, I will assign ProductCode (assuming that is primary key/unique value per product) to the CommandArgument
for the button, so each button will have different argument when it is clicked

Sample code may look like this

protected void RepeaterListOfProducts_OnItemDataBound(object sender, RepeaterItemEventArgs e)
{
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
{

Product product = (Product)e.Item.DataItem;

Literal productCode = (Literal)e.Item.FindControl("LiteralProdcutCode");
productCode.Text = product.ProdcutCode;

Literal productName = (Literal)e.Item.FindControl("LiteralProdcutName");
productName.Text = product.ProdcutName;

Literal productPrice = (Literal)e.Item.FindControl("LiteralProductPrice");
productPrice.Text = product.ProductPrice;

Button update = (Button)e.Item.FindControl("ButtonEditProduct");
update.CommandArgument = product.ProductCode;

}

}

Now comes the interesting part, in you OnItemCommand, I will take the command button argument and setup a predefined text box (in a differnt panel) with the value
and let the user update the price in a panel

protected void RepeaterListOfUsers_OnItemCommand(object sender, RepeaterCommandEventArgs e)
{
if (e.CommandName == "Edit")
{
LiteralUpdateProductCode.Text = e.CommandArgument.ToString();
TextBoxUpdatePrice.Text = ((Literal)e.Item.FindControl("LiteralProductPrice")).Text;
//add your custom logic here

}
}

The above codes takes the price and code from the repeater items and allows user to update with your custom logic.

In the panel, I could also have another button, which will perform my custom logic.

This code can be extended to include ‘Delete’ operation as well.

Thanks

CSS Friendly RadioButtonList

It was lovely Monday afternoon and a designer from team and said, “Hey Naveed!, can you do the same thing with <asp:RadioButtonList> as you did with CheckBoxList and make it accessible and I would also like to have a “class” on the selected radiobutton, so i can replace it with an image from CSS”

I said, “Your wish is my command, maestro!”.

Taking the similar approach as in this post, we create a custom ULRadioButtonList class, extend it to have two extra properties

1. ItemCssClass          //class attribute for non-selected item
2. ItemSelectedCssClass  //class attribute for selected class

Modify the Render() method to assign these attributes to selected or non-selected radio button’s <li>.

Here is the complete code snippet

[ToolboxData("<{0}:ULRadioButtonList runat=server></{0}:ULRadioButtonList>")]
public class ULRadioButtonList : RadioButtonList
{
public string ItemCssClass { get; set; }
public string ItemSelectedCssClass { get; set; }

protected override void Render(HtmlTextWriter writer)
{

// We start our un-ordered list tag.
writer.WriteBeginTag("ul");

// If the CssClass property has been assigned, we will add
// the attribute here in our <ul> tag.
if (this.CssClass.Length > 0)
{
writer.WriteAttribute("class", this.CssClass);
}

// We need to close off the <ul> tag, but we are not ready
// to add the closing </ul> tag yet.
writer.Write(">");

// Now we will render each child item, which in this case
// would be our checkboxes.
for (int i = 0; i < this.Items.Count; i++)
{
// We start the <li> (list item) tag.
writer.WriteBeginTag("li");

//if the radio button is selected and
//ItemSelectedCssClass  property is set then add attribute of
//class with ItemSelectedCssClass
if (this.Items[i].Selected && !string.IsNullOrEmpty(ItemSelectedCssClass))
{
writer.WriteAttribute("class", this.ItemSelectedCssClass);

}

//add a normal item class if that has been set
else if (!string.IsNullOrEmpty(ItemCssClass))
{
writer.WriteAttribute("class", this.ItemCssClass);
}
writer.Write(">");

this.RenderItem(ListItemType.Item, i, new RepeatInfo(), writer);

// Close the list item tag.
writer.WriteEndTag("li");
}

// We finish off by closing our un-ordered list tag.
writer.WriteEndTag("ul");
}
}

Modify the web.config or user control’s .ascx file as

<%@ Register Assembly="Web.Helper" TagPrefix="myControls"  Namespace="Web.Helper.WebControls" %>

Add your customised ULRadioButtonList as

<myControls:ULRadioButtonList runat="server"  CssClass="list" ID="myRadioButtonList" />

Bind the DataSource property as

myRadioButtonList.DataSource = myItems; myRadioButtonList.DataBind();

Remove any build errors, deploy and view source of the page

If you have read so far, your wish has also been completed

Cheers !

CSS Friendly CheckboxList

There have been several times when a designer has come to me with a grumpy face and said “Hey Naveed!, this <asp:CheckBoxList runat=”server” ID=”myCheckBoxList”/> spits out <span> or <table> tags instead of <ul> and <li> tags for list items.  It doesn’t match my templated HTML/CSS and is not going to pass W3C validation, can you fix it please?”

This issue is actually fixed in .NET 4 (why it took Microsoft so long, don’t know), but if you are not using .NET 4 then here is a simple server side control which you can use to render items as unordered list

Step 1: Add a new class file from VS and name it as ULCheckBoxList

Step 2: Inherit the class from standard .NET CheckBoxList

Step 3: Overwrite the Render() method of the control

Complete code snippet is given below

[ToolboxData("<{0}:ULCheckBoxList runat=server></{0}:ULCheckBoxList>")]  public class ULCheckBoxList : CheckBoxList
 {
 protected override void Render(HtmlTextWriter writer)
 {
 // We start our un-ordered list tag.
 writer.WriteBeginTag("ul");
 // If the CssClass property has been assigned, we will add // the attribute here in our <ul> tag.
 if (this.CssClass.Length > 0)
 {
 writer.WriteAttribute("class", this.CssClass);
 }
 // We need to close off the <ul> tag, but we are not ready // to add the closing </ul> tag yet.
 writer.Write(">");
 // Now we will render each child item, which in this case // would be our checkboxes.
 for (int i = 0; i < this.Items.Count; i++)
 {
 // We start the <li> (list item) tag.
 writer.WriteBeginTag("li");
 writer.Write(">");
 this.RenderItem(ListItemType.Item, i, new RepeatInfo(), writer);
 // Close the list item tag. 
 writer.WriteEndTag("li");
 }
 // We finish off by closing our un-ordered list tag.
 writer.WriteEndTag("ul");
 }
 }

In your web.config or in your control’s .ascx add the reference to the control something like

<%@ Register Assembly="Web.Helper" TagPrefix="myControls" Namespace="Web.Helper.WebControls" %>

and use it as

<myControls:ULCheckBoxList runat="server"  CssClass="list" ID="myCheckBoxList" /> 

Set the DataSource for the control in code behind and bind the data something like

myCheckBoxList.DataSource = myItems; myCheckBoxList.DataBind(); 

Enjoy!