Monday 14 May 2007

developing an embedded control in SPS 2003 webpart

over the last week I tried to develop a data control like a datalist or repeater that will have a child control which shares the same functionality as its parent i.e. another datalist or repeater. The goal of this is when the user clicks on the item on the parent level, the child level repeater will show up.

As we all know that programmers developing web part for sharepoint won't be able to enjoy the laziness of drag & drop as in ASP.net design view unless you use smartpart. (However I've seen someone on the net has said something that we shouldn't use smartpart for commercial app development, therefore, we stick to the grafting handcode :D ) We need the customized template class of repeater which derives from ITemplate interface. And easily you can implement this by minimum requirement of InistantiateIn which you create all your child controls and add them to the repeater control tree referred as container in the following part.

So the class might look like


using Sytem.Collections;
using System.Web.UI.WebControls;
namespace whatever...
{
public class MyTemplate: ITemplate
{
private string columnName;
private Repeater childRepeater;
public MyTemplate(string _columnName)
{
//constructor logic here
columnName = _columnName;
}
public void Instantiate(Control container)
{
LinkButton btnName = new LinkButton();
//style up your links in here if you like

//the embedded or possible recursive magic goes here
// in the databinding event.
btnName.DataBinding+= new EventHandler(btnName_DataBinding);
container.Controls.Add(btnName);
}
}

Then you start coding your event handler by using the object which initiates the event, i.e. your linkbutton and add in your command arg which you get the id or whatever you specify to know which button actually has been clicked.

public void btnName_DataBinding(object sender, EventArgs e)
{
LinkButton thisButton = (LinkButton)sender;

RepeaterItem container = (RepeaterItem)thisButton.NamingContainer;
//get the clicked data from datasource
string strVariable = Convert.ToString(DataBinder.Eval(((RepeaterItem)container).DataItem,columnName));
thisButton.CommandArgument = strVariable ;
thisButton.Text = strVariable;

//then you bind the child repeater that will call back the //recursive method
BindChildRepeater(container, strVariable);
}


Then you need to decide one thing. Do you or can you make your template recusive. Because sometimes your child repeater is simply different from the parent repeater in terms of control structure.like it got buttons , image or hyperlinks in it, if you use recursive method, it doesn't really make any sense because they are not the same thing... But if you are sure it's the same control type, as in this example, the child repeater will be having linkbuttons as well, just do it :)

///summary: then in the bindchildrepeater method, you bind embedded repeater
private void BindChildRepeater(RepeaterItem container, string colName)
{
//say you get a customized list somewhere from sharepoint data
MyList mySPList = new MyList();

//populate your list

if(mySPList !=null)
{


childRepeater = new Repeater();
//recursive data bind method called
childRepeater.ItemTemplate = new MyTemplate ("FirstName");
// or you just can't be bothered and use something //else, it's equally cool like following
// childRepeater.ItemTemplate = new ChildTemplate("FirstName","SecondName","Contact");
childRepeater.ItemCommand+= new RepeaterEventHandler(childRepeater_ItemCommand);
childRepeater.DataSource = mySPList;
childRepeater.ID = "childRepeater"+colName;
childRepeater.DataBind();

childRepeater.Visible=false;
// add this repeater to it's parent
container.Parent.Controls.Add(childRepeater);

}

}



There , you have a repeater inside a repeater(or whatever levels you have in the control tree, it will repeat until it reaches the leaf if recursive). So as you have seen, I set up an ID for this child repeater(s) so I will be able to find it through e.g. FindControl("childRepeaterJohhson"). Then when I click the control, I simply sert the control's visibility to true in order to show it after the postback.

Above works no problem at all, but there's one problem (big one)when I bind my child repeater this way, the ItemCommand event when you click the child repeater seems not bubbling up to the parent repeater , therefore, when you click the child repeater item i.e. a linkbutton, the ItemCommand Event won't fire in the web part. If anyone care to tell me where I did wrong and correct me, it will be highly appreciated. Thanks!