Below you can see that I have created a new List Page with a PipeLineGraphic for a Custom Entity.

The List Page has been created using the ListPage specialised class of the .NET API.

You can see the code below.

////////////////////Code Starts//////////////////

using Sage.CRM.WebObject;
using Sage.CRM.Blocks;
using Sage.CRM.Controls;
using Sage.CRM.Data;
using Sage.CRM.Utils;
using Sage.CRM.Graphics;
using Sage.CRM.UI;

namespace ProjectList
public class ProjectList : ListPage
/* Constructor needs EntityName, ListName, IdField, FilterByField, FilterContext and ScreenName
public ProjectList()
: base("project", "ProjectGrid", "ProjectSearchBox")
int iDomKey = Keys[(int)Sage.KeyList.DominantKey];
switch (iDomKey)
case 1:
FilterByField = "proj_companyid";
FilterByContextId = (int)Sage.KeyList.CompanyId;
case 2:
FilterByField = "proj_personid";
FilterByContextId = (int)Sage.KeyList.PersonId;
case 4:
FilterByField = "proj_userid";
FilterByContextId = (int)Sage.KeyList.UserId;
case 5:
FilterByField = "proj_channelid";
FilterByContextId = (int)Sage.KeyList.ChannelId;
FilterByField = "proj_userid";
FilterByContextId = (int)Sage.KeyList.UserId;

foreach (Entry myEntry in FilterScreen)
myEntry.NewLine = true;
myEntry.DefaultValue = null;
myEntry.Required = false;

string statusArg = Dispatch.QueryField("proj_status");
if (statusArg!=null)
ResultsGrid.Filter = "proj_status=" + statusArg;
if (statusArg == "''")
ResultsGrid.Filter = "proj_status is null";

public override void AddNewButton()

public override void BuildContents()

PipelineGraphicBlock myPipe = new PipelineGraphicBlock();
int intUserID = CurrentUser.UserId;

myPipe.PipelineStyle(PipelineStyles.SelectedWidth, "1");
myPipe.PipelineStyle(PipelineStyles.SelectedHeight, "10");
myPipe.PipelineStyle(PipelineStyles.PipeWidth, "40");
myPipe.PipelineStyle(PipelineStyles.PipeHeight, "60");
myPipe.PipelineStyle("Margin", "80");
myPipe.PipelineStyle("ShowLegend", "true");

string strSQL = "select proj_status, count(*) as t from project with (nolock) where proj_userid=" + intUserID + " group by proj_status";
QuerySelect queryObj = new QuerySelect();
queryObj.SQLCommand = strSQL;
string strStage = "";
while (!queryObj.Eof())
if (queryObj.FieldValue("t") != "0")
strStage = Metadata.GetTranslation("proj_status", queryObj.FieldValue("proj_status"));
myPipe.AddPipeEntry(strStage, System.Convert.ToInt32(queryObj.FieldValue("t")), queryObj.FieldValue("t") + " " + strStage, UrlDotNet(ThisDotNetDll, "RunProjectList") + "&proj_status='" + queryObj.FieldValue("proj_status") + "'");

myPipe.Summary = "Additional Information can be displayed here.";

HTMLString htmlPipe = new HTMLString();
htmlPipe.Html = myPipe.Execute();
string strhtmlPipe = htmlPipe.ToHtml().Replace("NAME=\"EntryForm\"", "NAME=\"EntryForm1\"");


////////////////////////Code Ends/////////////////////////


  1. The project uses the ListPage to constructor create the ProjectList.
  2. The constructor class looks at the context information and the page can be called from either the My CRM or the Team menus.
  3. The pipelinegraphic will add an additional filter 'proj_status'.  When a section of the pipeline is clicked this will be added to the URL and therefore needs to be read using the Dispatch.QueryField() method.
  4. The pipelinegraphicblock needs to be built ahead of the main ListPage behaviour.  This is done by using a BuildContents() override.
  5. The pipelinegraphicblock was created using one of the snippets provided by the Sage CRM SDK.
  6. When a pipelinegraphic section is clicked the URL will be changed and the page reloaded with the additional filter information.
  7. Additional Summary Information can be included by setting the Summary property.
  8. To avoid the inclusion of the pipelinegraphic creating a duplicate HTML form tag this needs to be removed.
  9. The pipeline can then be added to the contents of the page and sent to the browser.