For example, if some BLC contains a Categories data view and a Related Products data view, you would specify the Categories view to be the data source for the master grid and the Products view to be the data source for the details grid. When a category is selected in the master grid, all products associated with that category will be displayed in the details grid from the Products data view.
public class ProductCategories : PXGraph<ProductCategories>
{
#region Actions
public PXSave<Category> Save;
public PXCancel<Category> Cancel;
#endregion
#region Data Members
public PXSelect<Category> Categories;
public PXSelect<CategoryProduct,
Where<CategoryProduct.categoryID,
Equal<Current<Category.categoryID>>>> CategoryProducts;
#endregion
#region Event Handlers
protected virtual void Category_RowSelected(PXCache sender, PXRowSelectedEventArgs e)
{
this.CategoryProducts.Cache.AllowInsert = e.Row != null;
}
#endregion
}
As shown in the code snippet above, the detail view is referenced with the master view via a Current BQL operator. Also, notice RowSelected event handler defined for the Category DAC to disable Insert button on the details grid if there is not a single record in the master grid.
The next step is to configure master-detail PXGrids in Aspx:
for the master grid set SyncPosition property to true, then define the AutoCallBack and OnChangeCommand properties as follows to accordingly refresh the detail grid every time a different record or no record at all will be selected in the master grid:
<px:PXGrid ID="masterGrid" runat="server" DataSourceID="ds" SkinID="Details"
SyncPosition="True" Caption="Categories" CaptionVisible="True" Width="100%">
<AutoCallBack Command="Refresh" Target="detailGrid" />
<OnChangeCommand Command="Refresh" Target="detailGrid" />
...
</px:PXGrid>
for the detail grid it's only required to define a Refresh CallbackCommand to force the master grid to select data along with the details grid. By doing the framework will raise the previously defined Category_RowSelected event handler and disable Insert button on the details grid in cases when there is no record in the master grid:
<px:PXGrid ID="detailGrid" runat="server" DataSourceID="ds" SkinID="Details"
Caption="Products" CaptionVisible="True" Width="100%">
<CallbackCommands>
<Refresh SelectControlsIDs="masterGrid" />
</CallbackCommands>
...
</px:PXGrid>
For the sake of better user experience, it's recommended to place master-detail PXGrids within a PXSplitContainer as shown in the code snippet below:
<px:PXSplitContainer runat="server" ID="sp" PositionInPercent="true" SplitterPosition="50"
SkinID="Horizontal" Orientation="Horizontal" Panel1MinSize="250" Panel2MinSize="250">
<AutoSize Enabled="true" Container="Window" />
<Template1>
<px:PXGrid ID="masterGrid" runat="server" DataSourceID="ds" SkinID="Details"
SyncPosition="True" Caption="Categories" CaptionVisible="True" Width="100%">
<AutoCallBack Command="Refresh" Target="detailGrid" />
<OnChangeCommand Command="Refresh" Target="detailGrid" />
<Levels>
<px:PXGridLevel DataMember="Categories">
<Columns>
...
</Columns>
</px:PXGridLevel>
</Levels>
<AutoSize Enabled="True" />
</px:PXGrid>
</Template1>
<Template2>
<px:PXGrid ID="detailGrid" runat="server" DataSourceID="ds" SkinID="Details"
Caption="Products" CaptionVisible="True" Width="100%">
<CallbackCommands>
<Refresh SelectControlsIDs="masterGrid" />
</CallbackCommands>
<Levels>
<px:PXGridLevel DataMember="CategoryProducts">
<Columns>
...
</Columns>
</px:PXGridLevel>
</Levels>
<AutoSize Enabled="True" />
</px:PXGrid>
</Template2>
</px:PXSplitContainer>
And here is how master-details PXGrids should look and operate inside an Acumatica webpage: