///
/// Used to add a header / toolbar to a Saleslogix grid view.
/// Note that this won't work inside of a dialog, for several reasons.
///
[DefaultProperty("GridTitle")]
[ToolboxData("<{0}:SlxGridHelper runat=server>{0}:SimpleGridToolbar>")]
[ParseChildren(true)]
public class SlxGridHelper : WebControl, INamingContainer
{
[Description("Title to be displayed above the grid")]
public String GridTitle { get; set; }
[Description("Whether to show the 'Add' button (GridTitle has to be set for this to work)"), DefaultValue(true)]
public bool ShowAddButton { get; set; }
[Description("Whether to show the 'Delete' button (GridTitle has to be set for this to work)"), DefaultValue(true)]
public bool ShowDeleteButton { get; set; }
[Description("Id of an existing button to use for the add action. This must be an IButtonControl.")]
public String AddButtonId { get; set; }
[Description("Id of an existing button to use for the delete action. This must be an IButtonControl.")]
public String DeleteButtonId { get; set; }
///
/// If true, then the datasource will be automatically set up
/// (pulling from the collection property set up in the child insert info)
///
[Description("If true, then the datasource will be automatically set up"), DefaultValue(false)]
public bool AutoBind { get; set; }
///
/// Set this to a comma-separated list of fields to pull (this is only necessary when pulling "deep" properties,
/// e.g., Contact.Account.MainPhone)
///
public String BindFieldNames { get; set; }
[Description("ID for the grid we need to display this header for")]
public String GridId { get; set; }
[Description("Specification for the popup form. The ChildInsertInfo needs to be filled in in order for all functionality to be enabled."),
DesignerSerializationVisibility(
DesignerSerializationVisibility.Content),
PersistenceMode(PersistenceMode.InnerProperty)]
public MyDialogSpecs DialogSpecs { get; set; }
[Description("Content of this template will be added to the toolbar, before the save button. GridTitle must be specified."),
TemplateContainer(typeof(SlxGridHelper)),
PersistenceMode(PersistenceMode.InnerProperty)]
public ITemplate ToolbarContent { get; set; }
private GridView _grid;
///
/// Retrieve a reference to the page-level work item.
/// This can be used to get to the main entity.
///
private PageWorkItem WorkItem
{
get
{
return ((Sage.Platform.Application.UI.Web.ApplicationPage)Page).PageWorkItem;
/*
* This is from the FAQ but not working as of 7.5
IPageWorkItemLocator locatorService = Sage.Platform.Application.ApplicationContext.Current.Services.Get();
return locatorService.GetPageWorkItem();
*/
}
}
private WebEntityListBindingSource _dataSource;
///
/// Create (if necessary) and return the data source used for the grid.
/// By default this creates a datasource pulling from the property specified under ChildInsertInfo.
///
protected virtual WebEntityListBindingSource DataSource
{
get
{
if (_dataSource == null)
{
_dataSource = new WebEntityListBindingSource(DialogSpecs.ChildInsertInfo.ChildEntityType,
DialogSpecs.ChildInsertInfo.ParentEntityType,
DialogSpecs.ChildInsertInfo.ParentsCollectionPropertyName,
System.Reflection.MemberTypes.Property);
}
return _dataSource;
}
}
///
/// Tie event handlers to the (optional) specified buttons.
///
///
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (!String.IsNullOrEmpty(AddButtonId))
{
var btnAdd = ((IButtonControl)Parent.FindControl(AddButtonId));
if (btnAdd == null)
throw new InvalidOperationException("Unable to locate button '" + AddButtonId + "'");
btnAdd.Click += new EventHandler(btnAdd_Click);
}
if (!String.IsNullOrEmpty(DeleteButtonId))
{
var btnDelete = ((IButtonControl)Parent.FindControl(DeleteButtonId));
if (btnDelete == null)
throw new InvalidOperationException("Unable to locate button '" + DeleteButtonId + "'");
btnDelete.Click += new EventHandler(btnDelete_Click);
}
}
///
/// Tie event handlers for the grid.
///
///
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (Visible)
{
_grid = Parent.FindControl(GridId) as GridView;
if (_grid == null)
throw new InvalidOperationException("Unable to locate grid id '" + GridId + "'");
if (_grid.DataKeyNames == null || _grid.DataKeyNames.Length == 0)
_grid.DataKeyNames = new String[] { "Id" };
_grid.RowDataBound += new GridViewRowEventHandler(grid_RowDataBound);
_grid.RowEditing += new GridViewEditEventHandler(grid_RowEditing);
if (this.AutoBind)
{
DataSource.Bindings.Add(new WebEntityListBinding(DialogSpecs.ChildInsertInfo.ParentsCollectionPropertyName,
_grid));
}
if(_grid.AllowSorting)
_grid.Sorting += new GridViewSortEventHandler(delegate { });
if(_grid.AllowPaging)
_grid.PageIndexChanging += new GridViewPageEventHandler(grid_PageIndexChanging);
}
}
///
/// Bind the grid.
///
///
protected override void OnPreRender(EventArgs e)
{
base.OnPreRender(e);
if (Visible &&
this.AutoBind)
{
object currentEntity = WorkItem.Services.Get().GetEntity();
if (currentEntity != null)
{
DataSource.SourceObject = currentEntity;
if (!String.IsNullOrEmpty(BindFieldNames))
DataSource.BindFieldNames = BindFieldNames.Split(new char[] { ',' })
.Select(s => s.Trim())
.ToArray();
WorkItem.Services.Get().WatchBindingSource(DataSource);
DataSource.Bind();
}
}
}
///
/// Set up event handlers for clicking on the grid's rows
///
///
///
void grid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
if (DialogSpecs != null)
{
e.Row.Attributes.Add("ondblclick",
Page.ClientScript.GetPostBackEventReference(_grid, "Edit$" + e.Row.RowIndex.ToString()));
}
e.Row.Attributes.Add("onclick",
Page.ClientScript.GetPostBackEventReference(_grid, "Select$" + e.Row.RowIndex.ToString()));
if (e.Row.RowIndex == _grid.SelectedIndex)
{
// for some reason Saleslogix f. this one up
e.Row.CssClass += _grid.SelectedRowStyle.CssClass;
}
}
}
///
/// Handler to open the edit form when they want to edit a row.
///
///
///
void grid_RowEditing(object sender, GridViewEditEventArgs e)
{
string id = (string)_grid.DataKeys[e.NewEditIndex].Value;
IWebDialogService dlgService = WorkItem.Services.Get();
dlgService.SetSpecs(DialogSpecs.TopPosition, DialogSpecs.LeftPosition, DialogSpecs.DialogHeight,
DialogSpecs.DialogWidth, DialogSpecs.ActiveSmartPartID, DialogSpecs.Title, DialogSpecs.CenterDialog);
dlgService.EntityType = this.DialogSpecs.ChildInsertInfo.ChildEntityType;
dlgService.EntityID = id;
dlgService.ShowDialog();
}
void grid_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
_grid.PageIndex = e.NewPageIndex;
}
///
/// Delete the selected record (the confirmation dialog is assumed to have already been done, client-side)
///
///
///
void btnDelete_Click(object sender, EventArgs e)
{
int selectedIndex = _grid.SelectedIndex;
if (selectedIndex >= 0)
{
string id = (string)_grid.DataKeys[selectedIndex].Value;
if (String.IsNullOrEmpty(id))
throw new InvalidOperationException("Grid DataKey is empty - did you set DataKeyNames?");
IPersistentEntity child = (IPersistentEntity)EntityFactory.GetById(DialogSpecs.ChildInsertInfo.ChildEntityType, id);
if (child != null)
{
// remove reference from the parent's collection
object parentEntity = WorkItem.Services.Get().GetEntity();
object parentCollection = DialogSpecs.ChildInsertInfo.ParentsCollectionProperty.GetValue(parentEntity, null);
MethodInfo funRemove = parentCollection.GetType().GetMethod("Remove");
funRemove.Invoke(parentCollection, new object[] { child });
// THEN we can delete the entity
child.Delete();
// make sure we refresh all updatepanels
WorkItem.Services.Get().RefreshAll();
}
}
}
///
/// Pop up the edit form for an add.
/// This requires the ChildInsertInfo and DialogSpecs to be fully populated.
///
///
///
void btnAdd_Click(object sender, EventArgs e)
{
IWebDialogService dlgService = WorkItem.Services.Get();
dlgService.SetSpecs(DialogSpecs.TopPosition, DialogSpecs.LeftPosition, DialogSpecs.DialogHeight,
DialogSpecs.DialogWidth, DialogSpecs.ActiveSmartPartID, DialogSpecs.Title, DialogSpecs.CenterDialog);
dlgService.EntityType = DialogSpecs.ChildInsertInfo.ChildEntityType;
dlgService.SetChildIsertInfo(
DialogSpecs.ChildInsertInfo.ChildEntityType,
DialogSpecs.ChildInsertInfo.ParentEntityType,
DialogSpecs.ChildInsertInfo.ParentReferenceProperty,
DialogSpecs.ChildInsertInfo.ParentsCollectionProperty);
dlgService.ShowDialog();
}
///
/// If the "GridTitle" was specified we'll create the header table here (optionally including add
/// and delete button)
///
protected override void CreateChildControls()
{
base.CreateChildControls();
if (!String.IsNullOrEmpty(GridTitle))
{
Controls.Add(CreateHeaderTable());
}
}
public override void DataBind()
{
EnsureChildControls();
base.DataBind();
}
///
/// Create the caption/toolbar line for the grid.
///
///
private Control CreateHeaderTable()
{
Table tblHeader = new Table();
tblHeader.CssClass = "mainContentHeaderTable";
tblHeader.Style.Add("width", "100%");
TableRow tblRow = new TableRow();
TableCell tblCell = new TableCell();
tblCell.Text = GridTitle;
tblRow.Cells.Add(tblCell);
tblCell = new TableCell();
tblCell.CssClass = "mainContentHeaderToolsRight";
if (ToolbarContent != null)
{
PlaceHolder contentPlaceholder = new PlaceHolder();
tblCell.Controls.Add(contentPlaceholder);
ToolbarContent.InstantiateIn(contentPlaceholder);
}
if (ShowAddButton)
{
ImageButton btnAdd = new ImageButton();
btnAdd.ID = "btnAdd";
btnAdd.AlternateText = "Add Record";
btnAdd.ImageUrl = "ImageResource.axd?scope=global&type=Global_Images&key=Plus_16x16";
((IButtonControl)btnAdd).Click += new EventHandler(btnAdd_Click);
tblCell.Controls.Add(btnAdd);
}
if (ShowDeleteButton)
{
ImageButton btnDelete = new ImageButton();
btnDelete.ID = "btnDelete";
btnDelete.AlternateText = "Delete Selected Record";
btnDelete.ImageUrl = "ImageResource.axd?scope=global&type=Global_Images&key=Delete_16x16";
btnDelete.OnClientClick = "return confirm('Are you sure you wish to delete this record?')";
((IButtonControl)btnDelete).Click += new EventHandler(btnDelete_Click);
tblCell.Controls.Add(btnDelete);
}
// todo - we should have a way to add control from the form's definition
tblRow.Cells.Add(tblCell);
tblHeader.Rows.Add(tblRow);
return tblHeader;
}
#region Design time support
///
/// Wrap around DialogSpecs to get the properties to show up correctly in the form designer.
///
public class MyDialogSpecs : WebDialogSpecs
{
public MyDialogSpecs()
{
base.ChildInsertInfo = new MyChildInsertInformation();
}
public new MyChildInsertInformation ChildInsertInfo
{
get
{
return this.MyChildInsertInfo;
}
}
[DesignerSerializationVisibility(
DesignerSerializationVisibility.Content),
PersistenceMode(PersistenceMode.InnerProperty)]
public MyChildInsertInformation MyChildInsertInfo
{
get
{
return (MyChildInsertInformation)base.ChildInsertInfo;
}
set
{
base.ChildInsertInfo = value;
}
}
}
///
/// Wrapper for ChildInsertInfo to enable support in the designer.
///
public class MyChildInsertInformation : ChildInsertInformation
{
public String ParentEntityTypeName
{
set
{
base.ParentEntityType = Type.GetType(value);
if (base.ParentEntityType == null)
throw new InvalidOperationException("The value '" + value + "' cannot be converted to a type");
}
}
public String ChildEntityTypeName
{
set
{
base.ChildEntityType = Type.GetType(value);
if (base.ChildEntityType == null)
throw new InvalidOperationException("The value '" + value + "' cannot be converted to a type");
}
}
public String ParentReferencePropertyName { get; set; }
public String ParentsCollectionPropertyName { get; set; }
public new PropertyInfo ParentReferenceProperty
{
get
{
return ChildEntityType.GetProperty(ParentReferencePropertyName);
}
}
public new PropertyInfo ParentsCollectionProperty
{
get
{
return ParentEntityType.GetProperty(ParentsCollectionPropertyName);
}
}
}
#endregion
}