Grid / Grid Features / Master - Details
In This Topic
    Master - Details
    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:

    1. Given the count of the details in the details collection, determine the number of rows that are needed to show these details.
    2. 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:

    1. 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.
    2. 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) };
      };