Why does my PXSelector ignore what I have selected - acumatica

I have created a PXGraphExtension on POLandedCostDocEntry. I have added a PXAction button. When the button is pressed I show a popup panel to ask the user for a landed cost code.
The problem is that the PXSelector ignores whatever I enter into the field and resets to APPLE (or whatever Landed Cost Code is alphabetically first). If I use the Selector to choose a different code, the code I select is visible for a moment and then immediately replaced with APPLE again.
The ASPX for the popup dialog is as follows:
<px:PXSmartPanel runat="server" ID="PanelAskForLCCode" LoadOnDemand="True" AutoRepaint="True" Key="LandedCostCodeSelection" CaptionVisible="True" Caption="Select Landed Cost Code" AcceptButtonID="CstButton4" CancelButtonID="CstButton5">
<px:PXPanel runat="server" ID="CstPanel9">
<px:PXFormView runat="server" ID="CstFormView10" SkinID="Transparent" Width="100%" SyncPosition="True" DataMember="LandedCostCodeSelection" DataSourceID="ds">
<Template>
<px:PXSelector runat="server" ID="CstPXSelector11" DataField="LandedCostCodeID" CommitChanges="True" DataSourceID="ds">
</px:PXSelector>
</Template>
</px:PXFormView>
</px:PXPanel>
<px:PXPanel runat="server" ID="LandedCostCodeSelectionButtons" SkinID="Buttons">
<px:PXButton runat="server" ID="CstButton4" DialogResult="OK" Text="OK" />
<px:PXButton runat="server" ID="CstButton5" DialogResult="Cancel" Text="Cancel" />
</px:PXPanel></px:PXSmartPanel>
The code for the view that I'm referencing in the dialog is:
public PXSelect<LandedCostCode> LandedCostCodeSelection;
The code that I'm using to call the dialog is:
if (LandedCostCodeSelection.AskExt() == WebDialogResult.OK)
{
//rest of code here
}
What am I missing to allow the user to select or type a different Landed Cost Code?
Edit 1:
I have changed the code for the view that I'm referencing in the dialog to:
public PXFilter<LandedCostCode> LandedCostCodeSelection;
My aspx now looks like this:
<px:PXSmartPanel runat="server" ID="PanelAskForLCCode" Key="LandedCostCodeSelection" CaptionVisible="True" Caption="Select Landed Cost Code" AcceptButtonID="CstButton4" CancelButtonID="CstButton5" Width="300px" AutoRepaint="True" LoadOnDemand="True">
<px:PXFormView runat="server" ID="CstFormView18" CaptionVisible="False" Caption="LC Code Selection" DataSourceID="ds" DataMember="LandedCostCodeSelection">
<Template>
<px:PXLayoutRule runat="server" ID="CstPXLayoutRule19" StartColumn="True" ControlSize="XM" LabelsWidth="S"/>
<px:PXSelector runat="server" ID="CstPXSelector20" DataField="LandedCostCodeID" CommitChanges="True" DataSourceID="ds" DataMember="LandedCostCodeSelection"/>
</Template>
<CallbackCommands>
<Search CommitChanges="True"/>
</CallbackCommands>
</px:PXFormView>
<px:PXPanel runat="server" ID="LandedCostCodeSelectionButtons" SkinID="Buttons">
<px:PXButton runat="server" ID="CstButton4" DialogResult="OK" Text="OK"/>
<px:PXButton runat="server" ID="CstButton5" DialogResult="Cancel" Text="Cancel"/>
</px:PXPanel>
</px:PXSmartPanel>
I'm calling the dialog as follows:
if (LandedCostCodeSelection.AskExt((graph, view) =>
{
LandedCostCodeSelection.Cache.Clear();
},true) == WebDialogResult.OK)
{
}
I notice that when I click on the selector button and pick a row from the selector (which briefly returns a value to the field which is then overwritten right away) when I click on the selector button again, the selector has remembered the record I last selected.
Finally, if I invoke the dialog as follows:
if (LandedCostCodeSelection.AskExt((graph, view) =>
{
LandedCostCodeSelection.Cache.Clear();
LandedCostCodeSelection.Current.LandedCostCodeID = "XYZ";
},true) == WebDialogResult.OK)
{
}
Then the field is populated with XYZ and if I click OK I can reference the value of XYZ. (But if I use the selector, then the value is cleared and cannot be accessed again.)

The problem relies in the definition of the DataView and the DAC used. I have reproduced the issue and this is what I've changed to make it work:
Use a new custom DAC as a source for your view. Note that the field is not bound and is not key (does not have IsKey = true, as in LandedCostCode.LandedCostCodeID:
[Serializable]
[PXHidden]
public partial class LandedCostCodeFilter: IBqlTable
{
#region LandedCostCodeID
public abstract class landedCostCodeID : PX.Data.BQL.BqlString.Field<landedCostCodeID> { }
[PXString(15, IsUnicode = true)]
//[PXUnboudDefault("APPLE")] //optional, to preselect a value
[PXUIField(DisplayName = "Landed Cost Code",Visibility=PXUIVisibility.SelectorVisible)]
[PXSelector(typeof(Search<LandedCostCode.landedCostCodeID>))]
public virtual String LandedCostCodeID {get; set}
#endregion
}
Change the DataView definition, using a PXFilter instead of PXSelect and use the new DAC
public PXFilter<LandedCostCodeFilter> LandedCostCodeSelection;
Correct that and your dialog should work.
Obs.
If you want to have a value pre-selected when you open the dialog, add [PXUnboudDefault("APPLE")] to the field in the DAC
Not sure how does your button definition look like, but here is what it should be:
public PXAction<POLandedCostDoc> SelectLandedCost;
[PXButton]
[PXUIField(DisplayName = "Select Landed Cost Code", MapEnableRights = PXCacheRights.Delete, MapViewRights = PXCacheRights.Delete)]
protected void selectLandedCost()
{
if(LandedCostCodeSelection.AskExt(true) != WebDialogResult.OK) return;
// do some stuff here
}
Also, my aspx code:
<px:PXSmartPanel runat="server" ID="PanelAskForLCCode" Caption="Select Landed Cost Code" CaptionVisible="True" Key="LandedCostCodeSelection">
<px:PXFormView runat="server" ID="CstFormView2" DataMember="LandedCostCodeSelection" SkinID="Transparent" DataSourceID="ds" Height="100%" Width="100%">
<Template>
<px:PXLayoutRule runat="server" ID="CstPXLayoutRule3" StartColumn="True" />
<px:PXSelector runat="server" ID="CstPXSelector4" DataField="LandedCostCodeID" CommitChanges="True" AutoRefresh="True" />
<px:PXPanel runat="server" ID="LandedCostCodeSelectionButtons" SkinID="Buttons">
<px:PXButton runat="server" ID="CstButton6" DialogResult="OK" Text="OK" />
<px:PXButton runat="server" ID="CstButton7" DialogResult="Cancel" Text="Cancel" /></px:PXPanel></Template></px:PXFormView></px:PXSmartPanel>

Related

How to make PXAction and PXUIFieldAttribute.SetEnabled Work

I do not know why my code is not working or something might be missing.
I am trying to do is use PXAction to disable as specific field, when I compile and run this it my browser would just load into infinity.
Thank you guys!
Here is my code
DAC:
#region RadnomTest
[PXDBString(20, IsUnicode = true)]
[PXUIField(DisplayName = "Random Test")]
public virtual string RadnomTest { get; set; }
public abstract class radnomTest : BqlString.Field<radnomTest> { }
#endregion
GRAPH
#region Toggle Readonly
public PXAction<ClientProfileNames> ReadonlyToggle;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Toggle Read-only")]
protected virtual void readonlyToggle(Events.RowSelected<ClientProfileNames> e)
{
var row = e.Row;
PXUIFieldAttribute.SetEnabled<ClientProfileNames.radnomTest>(e.Cache, row, true);
Actions.PressSave();
}
#endregion
PAGE
<asp:Content ID="cont1" ContentPlaceHolderID="phDS" Runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%" PrimaryView="ClinetInfosMain" TypeName="OnlyForTesting.Graph.Profile.ClientProfileNamesMaint">
<CallbackCommands>
</CallbackCommands>
</px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phF" Runat="Server">
<px:PXFormView ID="form" runat="server" DataSourceID="ds" Style="z-index: 100" Width="100%" DataMember="ClinetInfosMain" TabIndex="2900">
<Template>
<px:PXLayoutRule runat="server" StartRow="True" StartColumn="True"/>
<px:PXTextEdit ID="edRadnomTest" runat="server" AlreadyLocalized="False" DataField="RadnomTest" IsClientControl="True">
</px:PXTextEdit>
</Template>
<AutoSize Container="Window" Enabled="True" MinHeight="200" />
</px:PXFormView>
</asp:Content>
Field state should be set from the RowSelected event, and not as the result of an action such a button click.
If you need to set the enabled status based on the value of another field, I would recommend checking the PXUIEnabled attribute which will let you handle this in a declarative fashion: https://asiablog.acumatica.com/2016/11/pxuienabled-and-pxuirequired-attributes.html

Smart panel reopen when press OK

I have a smart panel, when i press OK button then panel close and reopen again. what am i doing wrng?
Please find my popup panel OK C# and popup html below.
// Popup open code.
public PXAction<MyDAC> openPopup;
[PXUIField(DisplayName = "Add", MapEnableRights = PXCacheRights.Select)]
//[PXInsertButton]
protected virtual IEnumerable OpenPopup(PXAdapter adapter) {
if(CauseSmartPanel.AskExt() == WebDialogResult.OK) {
}
return adapter.Get();
}
public PXAction<MyDAC> addEditOK;
[PXUIField(DisplayName = "", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select, Visible = false)]
public virtual IEnumerable AddEditOK(PXAdapter adapter) {
return adapter.Get();
}
<px:PXSmartPanel ID="pnlSmartCause" runat="server" CaptionVisible="True" Caption="My Smart Panel"
Style="position: static" LoadOnDemand="True" Key="CauseSmartPanel" AutoCallBack-Target="frmMyCommand"
AutoCallBack-Command="Refresh" DesignView="Content">
<px:PXFormView ID="frmMyCommand" runat="server" SkinID="Transparent" DataMember="CauseSmartPanel" DataSourceID="ds" EmailingGraph="">
<Template>
<px:PXLayoutRule runat="server" StartRow="true" ControlSize="M" LabelsWidth="SM" StartColumn="True" />
<px:PXSelector ID="edCauseId" CommitChanges="true" runat="server" AlreadyLocalized="False" DataField="CauseId" AutoRefresh="true">
</px:PXSelector>
<px:PXLayoutRule runat="server" StartRow="true" ControlSize="XM" LabelsWidth="SM" StartColumn="True" />
<px:PXRichTextEdit ID="edDesc" runat="server" AlreadyLocalized="False" DataField="Description">
</px:PXRichTextEdit>
<px:PXLayoutRule runat="server" StartRow="true" StartColumn="True" ControlSize="SM" LabelsWidth="M"></px:PXLayoutRule>
<px:PXSelector ID="edEditedBy" runat="server" AlreadyLocalized="False" DataField="EditedBy" AutoRefresh="true">
</px:PXSelector>
<px:PXPanel ID="PXPanel1" runat="server" SkinID="Buttons">
<px:PXButton ID="btnMyCommandOK" CommandSourceID="ds" CommandName="AddEditOK" SyncVisible="false" Text="OK" DialogResult="OK" runat="server"></px:PXButton>
<px:PXButton ID="btnMyCommandCancel" runat="server" DialogResult="Cancel" Text="Cancel" />
</px:PXPanel>
</Template>
</px:PXFormView>
</px:PXSmartPanel>
No idea why your popup is loading a second time, but perhaps as a workaround, you could consider checking whether the user has already provided an answer to the popup.
This is done by using the Answer property on the view. In your case, it might be something like this:
if (CauseSmartPanel.View.Answer == WebDialogResult.None)
{
if(CauseSmartPanel.AskExt() == WebDialogResult.OK) {
}
}

INTran Not showing LotNumberNbr

Good day
I have made a new Grid to show data from INTran(PX.Objects.IN.INTran)
I see there is a LotSerialNbr in the INTran DAC. But when I make a new PXSelect I don't see it in the "ADD DATA FIELDS" on my page.
I add the Lot/Serial Nbr(LotSerialNbr) when loading stock on the Inventory Receipts.
I have also checked INRegister and INTranSplit both not show the Lot Serial Nbr?
using System;
using PX.Data;
using PX.Objects.IN;
using PX.Objects.SO;
namespace Test
{
public class StockTransfer : PXGraph<StockTransfer>
{
public PXSave<MasterTable> Save;
public PXCancel<MasterTable> Cancel;
public PXFilter<MasterTable > MasterView;
public PXFilter<INTran> DetailsView;
[Serializable]
public class MasterTable : IBqlTable
{
}
[Serializable]
public class DetailsTable : IBqlTable
{
}
public PXSelect<INRegister> Register;
public PXSelect<INTran> INTran;
public PXSelect<INTranSplit > INTranSplit ;
}
}
How can I get the Lot Serial number to show on the grid?
edit here is the ASPX:
<%# Page Language="C#" MasterPageFile="~/MasterPages/FormDetail.master" AutoEventWireup="true" ValidateRequest="false" CodeFile="ABIT1111.aspx.cs" Inherits="Page_ABIT1111" Title="Untitled Page" %>
<%# MasterType VirtualPath="~/MasterPages/FormDetail.master" %>
<asp:Content ID="cont1" ContentPlaceHolderID="phDS" Runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%"
TypeName="JVDLocationTransfer.TransferGrap"
PrimaryView="MasterView"
>
<CallbackCommands>
</CallbackCommands>
</px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phF" Runat="Server">
<px:PXFormView ID="form" runat="server" DataSourceID="ds" DataMember="MasterView" Width="100%" Height="100px" AllowAutoHide="false">
<Template>
<px:PXLayoutRule ID="PXLayoutRule1" runat="server" StartRow="True"></px:PXLayoutRule>
<px:PXTextEdit runat="server" ID="CstPXTextEdit1" DataField="UsrFROMLocation" />
<px:PXTextEdit runat="server" ID="CstPXTextEdit2" DataField="UsrInventoryID" />
<px:PXTextEdit runat="server" ID="CstPXTextEdit3" DataField="UsrInventoryItemDescription" />
<px:PXTextEdit runat="server" ID="CstPXTextEdit4" DataField="UsrQty" />
<px:PXTextEdit runat="server" ID="CstPXTextEdit5" DataField="UsrReasonCode" />
<px:PXTextEdit runat="server" ID="CstPXTextEdit6" DataField="UsrSKU" />
<px:PXTextEdit runat="server" ID="CstPXTextEdit7" DataField="UsrUOM" /></Template>
</px:PXFormView>
</asp:Content>
<asp:Content ID="cont3" ContentPlaceHolderID="phG" Runat="Server">
<px:PXGrid ID="grid" runat="server" DataSourceID="ds" Width="100%" Height="150px" SkinID="Details" AllowAutoHide="false">
<Levels>
<px:PXGridLevel DataMember="INTran">
<Columns>
<px:PXGridColumn DataField="InventoryID" Width="70" />
<px:PXGridColumn DataField="LotSerialNbr" ></px:PXGridColumn></Columns>
</px:PXGridLevel>
</Levels>
<AutoSize Container="Window" Enabled="True" MinHeight="150" />
<ActionBar >
</ActionBar>
</px:PXGrid>
</asp:Content>
The screen graph JVDLocationTransfer.TransferGrap declared in ASPX doesn't match the target StockTransfer graph. Also inexistent columns are declared on dataview like MasterView which points to empty DACs like MasterTable. Wizards functionality such as Add Data Field won't work properly in that context.

How to refresh a grid from a redirected page

I have an inquiry page where the Header is the POLine table and the grid is a new table linked to POLine. I cannot use an unbounded DAC for the filters because I want to offer the option to navigate over existing records.
If I open the page directly and enter the POLine information, the grid is refreshed correctly.
I included a button in the Purchase Orders page with an action that opens my inquiry page. In this scenario, the filter is loaded correctly but the grid does not show the records until the grid's refresh button is pressed.
This is my Action:
public PXAction<POOrder> Reconcile;
[PXUIField(DisplayName = "Reconcile", MapEnableRights = PXCacheRights.Select, MapViewRights = PXCacheRights.Select)]
[PXButton(CommitChanges = true, OnClosingPopup = PXSpecialButtonType.Cancel)]
public virtual void reconcile()
{
POLine pOLineRow = Transactions.Current;
if (pOLineRow == null)
{
return;
}
if (pOLineRow.OrderNbr != null)
{
PEPOOrderReconciliationMaint pEPOOrderReconciliationgraph = PXGraph.CreateInstance<PEPOOrderReconciliationMaint>();
pEPOOrderReconciliationgraph.POOrderReconcileRecord.Current = pEPOOrderReconciliationgraph.POOrderReconcileRecord.Search<POLine.orderType, POLine.orderNbr, POLine.lineNbr>(pOLineRow.OrderType, pOLineRow.OrderNbr, pOLineRow.LineNbr, pOLineRow.OrderType);
if (pEPOOrderReconciliationgraph.POOrderReconcileRecord.Current != null)
{
throw new PXRedirectRequiredException(pEPOOrderReconciliationgraph, false, "PORECONCILIATION") { Mode = PXBaseRedirectException.WindowMode.NewWindow };
}
}
}
I have not used the Search<> method at a detail level before, but I found this Acumatica reference in POReceiptEntry:
POLineR polineR = _graph.purchaseLinesUPD.Search<POLineR.orderType, POLineR.orderNbr, POLineR.lineNbr>
(itemsource.OrderType, itemsource.OrderNbr, itemsource.LineNbr);
I also tried to assign the value directly with a PXSelect:
pEPOOrderReconciliationgraph.POOrderReconcileRecord.Current = PXSelect<POLine,Where<POLine.orderType,
Equal<Required<POLine.orderType>>,And<POLine.orderNbr,
Equal<Required<POLine.orderNbr>>,And<POLine.lineNbr,
Equal<Required<POLine.lineNbr>>>>>>
.Select(this, pOLineRow.OrderType, pOLineRow.OrderNbr, pOLineRow.LineNbr);
I don't think this is related to the error though. I think it's more oriented to a refresh option in the ASPX.
This is my ASPX code:
<%# Page Language="C#" MasterPageFile="~/MasterPages/FormDetail.master" AutoEventWireup="true" ValidateRequest="false" CodeFile="PR501000.aspx.cs" Inherits="Page_PR501000" Title="Untitled Page" %>
<%# MasterType VirtualPath="~/MasterPages/FormDetail.master" %>
<asp:Content ID="cont1" ContentPlaceHolderID="phDS" Runat="Server">
<px:PXDataSource ID="ds" runat="server" Visible="True" Width="100%" TypeName="Purchase.PEPOOrderReconciliationMaint" PrimaryView="POOrderReconcileRecord">
<CallbackCommands>
<px:PXDSCallbackCommand Name="SaveClose" Visible="false" PopupVisible="false"/>
<px:PXDSCallbackCommand Name="Save" Visible="false" CommitChanges="true"/>
<px:PXDSCallbackCommand Name="Cancel" Visible="true" CommitChanges="true"/>
<px:PXDSCallbackCommand Name="Insert" Visible="false" CommitChanges="true"/>
<px:PXDSCallbackCommand Name="CopyPaste" Visible="false" CommitChanges="true"/>
<px:PXDSCallbackCommand Name="Delete" Visible="false" CommitChanges="true"/>
</CallbackCommands>
</px:PXDataSource>
</asp:Content>
<asp:Content ID="cont2" ContentPlaceHolderID="phF" Runat="Server">
<px:PXFormView ID="form" runat="server" DataSourceID="ds" Style="z-index: 100"
Width="100%" DataMember="POOrderReconcileRecord" TabIndex="4500">
<Template>
<px:PXLayoutRule runat="server" StartColumn="True">
</px:PXLayoutRule>
<px:PXDropDown ID="edOrderType" runat="server" DataField="OrderType">
</px:PXDropDown>
<px:PXSelector ID="edOrderNbr" runat="server" DataField="OrderNbr" AutoRefresh="True" CommitChanges="True">
</px:PXSelector>
<px:PXLayoutRule runat="server" StartColumn="True"/>
<px:PXSelector ID="edLineNbr" runat="server" CommitChanges="True" DataField="LineNbr">
</px:PXSelector>
</Template>
</px:PXFormView>
</asp:Content>
<asp:Content ID="cont3" ContentPlaceHolderID="phG" Runat="Server">
<px:PXGrid ID="grid" runat="server" DataSourceID="ds" Style="z-index: 100; margin-top: 0px;"
Width="100%" Height="150px" SkinID="Details" TabIndex="21000" KeepPosition="True" SyncPosition="True" AdjustPageSize="Manual">
<Levels>
<px:PXGridLevel DataKeyNames="OrderType,OrderNbr,LineNbr" DataMember="POReceiptLineRecord">
<RowTemplate>
<px:PXSegmentMask ID="edInventoryID" runat="server" DataField="InventoryID" CommitChanges="True" Size="M" Width="200px">
</px:PXSegmentMask>
<px:PXNumberEdit ID="edReceiptQty" runat="server" AlreadyLocalized="False" DataField="ReceiptQty" CommitChanges="True" Size="S">
</px:PXNumberEdit>
</RowTemplate>
<Columns>
<px:PXGridColumn DataField="InventoryID">
</px:PXGridColumn>
<px:PXGridColumn DataField="ReceiptQty" TextAlign="Right" Width="100px">
</px:PXGridColumn>
</Columns>
</px:PXGridLevel>
</Levels>
<AutoSize Container="Window" Enabled="True" MinHeight="150" />
</px:PXGrid>
</asp:Content>
This is the PEPOOrderReconciliationMaint code:
public class PEPOOrderReconciliationMaint : PXGraph<PEPOOrderReconciliationMaint, POLine>
{
public PXSelect<POLine> POOrderReconcileRecord;
public PXSelect<POReceiptLine,
Where<
POReceiptLine.pOType, Equal<Current<POLine.orderType>>,
And<POReceiptLine.pONbr, Equal<Current<POLine.orderNbr>>,
And<POReceiptLine.pOLineNbr, Equal<Current<POLine.lineNbr>>>>>> POReceiptLineRecord;
#region Cache Attached
#region OrderType
[PXDBString(2, IsFixed = true, IsKey = true)]
[POOrderType.List()]
[PXUIField(DisplayName = "Type", Enabled = true)]
protected virtual void POLine_OrderType_CacheAttached(PXCache Sender)
{
}
#endregion
#region OrderNbr
[PXDBString(15, IsUnicode = true, InputMask = "", IsKey = true)]
[PXUIField(DisplayName = "Order Nbr.", Visible = true)]
[PXSelector(typeof(Search<POOrder.orderNbr,
Where<POOrder.orderType, Equal<Current<POLine.orderType>>>>))]
protected virtual void POLine_OrderNbr_CacheAttached(PXCache Sender)
{
}
#endregion
#region LineNbr
[PXDBInt(IsKey = true)]
[PXUIField(DisplayName = "Line Nbr.", Visible = true, Enabled = true)]
[PXSelector(typeof(Search<POLine.lineNbr,
Where<POLine.orderNbr, Equal<Current<POLine.orderNbr>>,
And<POLine.orderType, Equal<Current<POLine.orderType>>>>>))]
protected virtual void POLine_LineNbr_CacheAttached(PXCache Sender)
{
}
#endregion
#endregion
}

How to create Master-Detail Grids in Acumatica?

I'm working on a custom page to visualize the relations between parent and child records by displaying the table data in a hierarchical order.
There are 2 data views in my BLC, which I'd like to use as the data source for two PXGrids to display the data in a master/detail format. When a record is selected in the master grid, all of the related child entries should be shown in the details grid.
How should I declare my 2 PXGrids in Aspx to accomplish this task?
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:

Resources