In This Topic
About Master - Details
Master - Details is a feature of the Table Grid that allows you to display additional information (details) for each NRecordDataRow (i.e. for each record). The following image demonstrates a master - details table grid:
In the image above the details for each person show the orders that are associated with that person. The details are managed by the NMasterDetails element, that can be accessed by the MasterDetails property. The following code example achieves the master - details grid shown above:
Master - Details Example |
Copy Code
|
// create a view and get its grid
NTableGridView view = new NTableGridView();
NTableGrid grid = view.Grid;
// bind the grid to personsDataSource
grid.DataSource = personsDataSource;
// get the grid master details
NMasterDetails masterDetails = grid.MasterDetails;
// creater the table grid detail. It shows information from the personOsOrdersDataSource
NTableGridDetail detail = new NTableGridDetail();
masterDetails.Details.Add(detail);
detail.DataSource = personOsOrdersDataSource;
// the details are bound using field binding
NRelationMasterBinding masterBinding = new NRelationMasterBinding();
masterBinding.Relations.Add(new NRelation("Id", "PersonId"));
detail.MasterBinding = masterBinding;
// configure the details grid
detail.GridView.Grid.AllowEdit = false;
|
Details
The Table Grid can display multiple details for each record data row. The details are contained inside the NDetailCollection, which is accessible from the Details property of the NMasterDetails element. The details are represented by objects that derive from the NDetails element. The following image shows the current details hierarchy:
Following are details for the classes in the hierarchy:
-
NDetail - this is the base class for all details that can reside in the details collection. The NDetail defines a Title property that can be displayed by the details presenter (see below). It also defines the following method:
public abstract NWidget CreateWidget(NDataSource masterDataSource, int masterRowIndex)
that all details must implement in order to create a widget that represents the detail for the specified data source record.
-
NDataSourceDetail - this is base class for all details that display information from a slave data source. To do that there should be some sort of relation between the master data source and the slave data source. This relation is specified by a master binding object that is accessible from the MasterBinding property.The slave data source is specified by the DataSource property. Currently implemented is the NRelationMasterBinding that essentially contains a collection of master - slave relation fields. In the Master - Details Example above the details grid displays the records from the personOsOrdersDataSource for which the PersonId field is equal to the record Id field.
-
NGridDetail - serves as base class for data source details that use a grid - Table Grid or Tree Grid - to display the records from the slave data source that relate to the master record. When a grid detail is asked to create a widget for the record detail, it creates a deep clone of the grid view accessible from the GridView property. In this way the grid that is aggregated inside the NGridDetail serves as template for the grids created for each record detail.
-
NTreeGridDetail and NTableGridDetail - these are grid details that display the slave records as a TreeGrid or TableGrid respectively. In the Master - Details Example above we have used a NTableGridDetail to show the slave records as a table grid.
-
NCustomDetail - this detail lets the developer create a custom widget that shows custom information about the record. The following code example demonstrates the custom details:
Custom Details |
Copy Code
|
// create the custom detail that creates a widget displaying information about the row.
NMasterDetails masterDetails = tableGrid.MasterDetails;
NCustomDetail customDetail = new NCustomDetail();
masterDetails.Details.Add(customDetail);
customDetail.CreateWidgetDelegate = delegate(NCustomDetailCreateWidgetArgs arg)
{
// get information about the data source row
string name = (string)arg.DataSource.GetValue(arg.RowIndex, "Name");
DateTime birthday = (DateTime)arg.DataSource.GetValue(arg.RowIndex, "Birthday");
string email = (string)arg.DataSource.GetValue(arg.RowIndex, "Email");
// display the information as a widget
NPairBox namePair = new NPairBox("Name:", name);
NPairBox birthdayPair = new NPairBox("Birthday:", birthday.ToString());
NPairBox emailPair = new NPairBox("Email:", email.ToString());
NStackPanel infoStack = new NStackPanel();
infoStack.VerticalSpacing = 2.0d;
infoStack.Add(namePair);
infoStack.Add(birthdayPair);
infoStack.Add(emailPair);
return infoStack;
};
|
Details Presenter
The details presenter is represented by an object that is derived from NDetailsPresenter class and an instance of which is accessible from the DetailsPresenter property of the NMasterDetails class. The details presenter is responsible for two things:
- Given the count of the details in the details collection, determine the number of rows that are needed to show these details.
- Create the NDetailsCell instances for each details row.
If a details presenter is not assigned to the NMasterDetails.DetailsPresenter property, by default the grid shows each detail in a single cell, positioned on a separate row.
The following image shows the current NDetailsPresenter class hierarchy:
As you can see currently there are two types of details presenters:
- NTabDetailsPresenter - this details presenter shows the details in a single NDetailsCell that contains a NTab widget. Each tab page represents a single detail widget. The tab pages titles are obtained from the Title property of each NDetail instance.
-
NCustomDetailsPresenter - this details presenter gives the developer the ability to provide a custom details presentation, as shown in the following example:
Custom Details Presenter |
Copy Code
|
NCustomDetailsPresenter customDetailsPresenter = new NCustomDetailsPresenter();
tableGrid.MasterDetails.DetailsPresenter = customDetailsPresenter;
customDetailsPresenter.GetDetailsRowCountDelegate = delegate(NCustomDetailsPresenterGetDetailsRowCountArgs args)
{
// represent the details in a single row, unless there are no details
return args.DetailCollection.Count == 0 ? 0 : 1;
};
customDetailsPresenter.CreateDetailRowCellsDelegate = delegate(NCustomDetailsPresenterCreateDetailRowCellsArgs args)
{
// create a list of [detail:widget] for all details that can create widgets
NList<NKeyValuePair<NDetail, NWidget>> detailsWidgets = new NList<NKeyValuePair<NDetail, NWidget>>();
int count = args.DetailCollection.GetChildrenCount();
for (int i = 0; i < count; i++)
{
NDetail detail = args.DetailCollection[i];
NWidget widget = detail.CreateWidget(args.MasterDataSource, args.MasterRowIndex);
if (widget != null)
{
detailsWidgets.Add(new NKeyValuePair<NDetail, NWidget>(detail, widget));
}
}
// no detail widgets -> embed nothing in the details row
if (detailsWidgets.Count == 0)
return null;
// single details -> embed it in the details row
if (detailsWidgets.Count == 1)
return new NDetailsCell[] { new NDetailsCell(detailsWidgets[0].Value) };
// create a stack of group boxes
NStackPanel stack = new NStackPanel();
for (int i = 0; i < detailsWidgets.Count; i++)
{
NKeyValuePair<NDetail, NWidget> detailsWidget = detailsWidgets[i];
NGroupBox groupBox = new NGroupBox(detailsWidget.Key.Title);
groupBox.Content = detailsWidget.Value;
stack.Add(groupBox);
}
return new NDetailsCell[] { new NDetailsCell(stack) };
};
|