This was a small request coming from a friend but I had the same question asked a few more times in the past so I decided to do a quick post, that way if it comes up again I can just send them this link.
OK, to the point: How do we make a XAF Web ListView selectable by groups?
Here is the code:
public class SelectGroupInListViewController : ViewController
{
public SelectGroupInListViewController()
{
TargetObjectType = typeof(Invoice);
// TargetViewNesting = Nesting.Root;
TargetViewType = ViewType.ListView;
}
/// <summary>
/// List view grid control
/// </summary>
private ASPxGridView Grid
{
get
{
ASPxGridListEditor editor = View != null ? (View as ListView).Editor as ASPxGridListEditor : null;
if (editor != null)
return editor.Grid;
return null;
}
}
protected override void OnViewControlsCreated()
{
base.OnViewControlsCreated();
if (Grid != null)
{
// Add checkboxes to group rows
Grid.ClientInstanceName = gridId;
Grid.Templates.GroupRowContent = new CheckboxGroupRowContentTemplate(gridId);
Grid.CustomCallback += Grid_CustomCallback;
Grid.HtmlRowPrepared += Grid_HtmlRowPrepared;
}
}
#region Group checkboxes
// http://www.devexpress.com/Support/Center/Example/Details/E1760
/// <summary>
/// SaleItem key field name
/// </summary>
//public const string keyFieldName = "ItemId";
/// <summary>
/// list view control name
/// </summary>
public const string gridId = "InvoiceListViewGrid";
protected void Grid_CustomCallback(object sender, ASPxGridViewCustomCallbackEventArgs e)
{
string[] parameters = e.Parameters.Split(';');
int index = int.Parse(parameters[0]);
string fieldname = parameters[1];
bool isGroupRowSelected = bool.Parse(parameters[2]);
ReadOnlyCollection<GridViewDataColumn> groupedCols = Grid.GetGroupedColumns();
if (groupedCols[groupedCols.Count - 1].FieldName == fieldname)
{
// Checked groupcolumn is the lowest level groupcolumn;
// we can apply original recursive checking here
Grid.ExpandRow(index, true); // Expand grouped column for consistent behaviour
for (int childIndex = 0; childIndex < Grid.GetChildRowCount(index); childIndex++)
{
var key = (Grid.GetChildRow(index, childIndex) as Invoice).Oid;
Grid.Selection.SetSelectionByKey(key, isGroupRowSelected);
}
}
else
{
// checked row is not the lowest level groupcolumn:
// we will find the Datarows that are to be checked recursively by iterating all rows
// and compare the fieldvalues of the fields described by the checked groupcolumn
// and all its parent groupcolumns. Rows that match these criteria are to the checked.
// CAVEAT: only expanded rows can be iterated, so we will have to expand clicked row recursivly before iterating the grid
// Get index of current grouped column
int checkedGroupedColumnIndex = -1;
foreach (GridViewDataColumn gcol in groupedCols)
{
if (gcol.FieldName == fieldname)
{
checkedGroupedColumnIndex = groupedCols.IndexOf(gcol);
break;
}
}
//Build dictionary with checked groupcolumn and its parent groupcolumn fieldname and values
Invoice checkedDataRow = Grid.GetRow(index) as Invoice;
Dictionary<string, object> dictParentFieldNamesValues = new Dictionary<string, object>();
string parentFieldName;
object parentKeyValue;
for (int i = checkedGroupedColumnIndex; i >= 0; i--)
{
// find parent groupcols and parentkeyvalue
GridViewDataColumn pcol = groupedCols[i];
parentFieldName = pcol.FieldName;
parentKeyValue = checkedDataRow.Oid;
dictParentFieldNamesValues.Add(parentFieldName, parentKeyValue);
}
bool isChildDataRowOfClickedGroup;
Grid.ExpandRow(index, true); // Expand grouped column for consistent behaviour
for (int i = 0; i <= Grid.VisibleRowCount - 1; i++)
{
Invoice row = Grid.GetRow(i) as Invoice;
// Check whether row does belong to checked group all the parent groups of the clicked group
isChildDataRowOfClickedGroup = true;
foreach (KeyValuePair<string, object> kvp in dictParentFieldNamesValues)
{
parentFieldName = kvp.Key;
parentKeyValue = kvp.Value;
if (row.Oid.Equals(parentKeyValue) == false)
{
isChildDataRowOfClickedGroup = false;
break;
//Iterated row does not belong to at least one parentgroup of the clicked groupbox; do not change selection state for this row
}
}
if (isChildDataRowOfClickedGroup == true)
{
// Row meets all the criteria for belonging to the clicked group and all parents of the clicked group:
// change selection state
Grid.Selection.SetSelectionByKey(row.Oid, isGroupRowSelected);
}
}
}
}
void Grid_HtmlRowPrepared(object sender, ASPxGridViewTableRowEventArgs e)
{
// Subscribe group checkboxes on CheckedChanged event
if (e.RowType == GridViewRowType.Group)
{
ASPxCheckBox checkBox = Grid.FindGroupRowTemplateControl(e.VisibleIndex, "checkBox") as ASPxCheckBox;
if (checkBox != null)
{
checkBox.Checked = GetChecked(e.VisibleIndex);
}
}
}
/// <summary>
/// Return checked state by selected childrens
/// </summary>
/// <param name="visibleIndex">Visible index of group row</param>
/// <returns>Is checked</returns>
protected bool GetChecked(int visibleIndex)
{
for (int childIndex = 0; childIndex < Grid.GetChildRowCount(visibleIndex); childIndex++)
{
//var key = Grid.GetChildRowValues(visibleIndex, childIndex, keyFieldName);
var key = (Grid.GetChildRow(visibleIndex, childIndex) as Invoice).Oid;
bool isRowSelected = Grid.Selection.IsRowSelectedByKey(key);
if (!isRowSelected)
return false;
}
return true;
}
#endregion Group checkboxes
}
/// <summary>
/// Group row with checkBox template
/// </summary>
public class CheckboxGroupRowContentTemplate : ITemplate
{
/// <summary>
/// Grid id for usng in inner scripts
/// </summary>
string gridId = "";
/// <summary>
/// ctor
/// </summary>
/// <param name="gridId">Grid id for usng in inner scripts</param>
public CheckboxGroupRowContentTemplate(string gridId)
{
this.gridId = gridId;
}
public void InstantiateIn(Control container)
{
// Add checkbox
ASPxCheckBox checkBox = new ASPxCheckBox();
checkBox.ID = "checkBox";
checkBox.Init += checkBox_Init;
container.Controls.Add(checkBox);
// Add caption
ASPxLabel label = new ASPxLabel();
label.Text = GetCaptionText((GridViewGroupRowTemplateContainer)container);
label.EncodeHtml = false;
container.Controls.Add(label);
}
void checkBox_Init(object sender, System.EventArgs e)
{
ASPxCheckBox checkBox = sender as ASPxCheckBox;
GridViewGroupRowTemplateContainer container = checkBox.NamingContainer as GridViewGroupRowTemplateContainer;
checkBox.ClientSideEvents.CheckedChanged = string.Format(
"function(s, e){{ {0}.PerformCallback('{1};{2};' + s.GetChecked()); }}",
gridId,
container.VisibleIndex,
container.Column.FieldName);
}
/// <summary>
/// Get caption text for container
/// </summary>
/// <param name="container">Container</param>
/// <returns>Caption</returns>
private string GetCaptionText(GridViewGroupRowTemplateContainer container)
{
string captionText = !string.IsNullOrEmpty(container.Column.Caption) ? container.Column.Caption : container.Column.FieldName;
return string.Format("{0} : {1} {2}", captionText, container.GroupText, container.SummaryText);
}
}
Now let’s see it in action:
Source Code: https://github.com/jjcolumb/BlogDemo
Until next time, XAF out!

