I have the following use case:
Acumatica combo box / dropdown, which can have 8 or so values, the selection of which determines the table / DAC used to present in a PXSelector.
e.g.:
-If user select option a, I need to show in PXSelector values from Table A
-If user select option b, I need to show in PXSelector values from Table B
-If user select option c, I need to show in PXSelector value from Table C
I understand that I'd have to use a Custom Selector Attribute, but the details of how to do this are not clear.
As you said, you need to implement an attribute that inherits from the PXCustomSelectorAttribute
class.
1- Create a class PromptType
that will have an ID
and Description
that will hold the types of each table.
public class PromptType
{
public Type Id { get; set;}
public Type Description { get; set; }
}
2- Implement the customSelectorAttribute, like this:
public class MyCustomSelector : PXCustomSelectorAttribute
{
//Class used to display the data into the selector
[Serializable]
public class TableDummy : IBqlTable
{
#region Id
[PXInt(IsKey = true)]
[PXUIField(DisplayName = "Id")]
public int? Id { get; set; }
public class id : IBqlField { }
#endregion
#region Description
[PXString(60, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Description", Visibility = PXUIVisibility.SelectorVisible)]
public string Description { get; set; }
public class description : IBqlField { }
#endregion
}
//Selected table
private Type _TableSelection;
//Tables Ids. You can add as much field ID as you want
private Type _TableFieldA;
private Type _TableFieldB;
private Type _TableFieldC;
//Tables description fields
private Type _TableAFieldDesc;
private Type _TableBFieldDesc;
private Type _TableCFieldDesc;
public MyCustomSelector(Type tableSelection, Type tableFieldA, Type tableAFieldDesc, Type tableFieldB, Type tableBFieldDesc, Type tableFieldC, Type tableCFieldDesc) : base(typeof(TableDummy.id))
{
_TableSelection = tableSelection;
_TableFieldA = tableFieldA;
_TableFieldB = tableFieldB;
_TableFieldC = tableFieldC;
_TableAFieldDesc = tableAFieldDesc;
_TableBFieldDesc = tableBFieldDesc;
_TableCFieldDesc = tableCFieldDesc;
}
//Get the name of the selected table by using the private field _TableSelection.
private string GetSelection()
{
var cache = _Graph.Caches[_BqlTable];
return cache.GetValue(cache.Current, _TableSelection.Name)?.ToString();
}
//Return a pompt instance based on the selected table in the dropdown.
private PromptType GetSelectedTableField(string selectedTable)
{
switch (selectedTable)
{
case "A":
return new PromptType() { Id = _TableFieldA, Description = _TableAFieldDesc };
case "B":
return new PromptType() { Id = _TableFieldB, Description = _TableBFieldDesc };
case "C":
return new PromptType() { Id = _TableFieldC, Description = _TableCFieldDesc };
default:
return new PromptType() { Id = _TableFieldA, Description = _TableAFieldDesc };
}
}
//Return the records
public IEnumerable GetRecords()
{
var selectedField = GetSelectedTableField(GetSelection());
var selectedTable = BqlCommand.GetItemType(selectedField.Id);
var select = BqlCommand.Compose(
typeof(Select<>),
selectedTable
);
var cmd = BqlCommand.CreateInstance(select);
PXView view = new PXView(_Graph, true, cmd);
foreach (var row in view.SelectMulti())
{
var id = (int?)view.Cache.GetValue(row, selectedField.Id.Name);
var description = view.Cache.GetValue(row, selectedField.Description.Name)?.ToString();
yield return new TableDummy { Id = id, Description = description };
}
}
}
You can change the constructor of the custom attribute, by passing the desired number of tables.
3- Once you have implemented your custom attribute, you can use it in your field like this:
#region DropDown to select a table
[PXDBString(1)]
[PXUIField(DisplayName = "Table Selection")]
[PXStringList(
new string[]
{
"A",
"B",
"C"
},
new string[]
{
"Table A",
"Table B",
"Table C"
})]
public virtual string UsrTableSelection { get; set; }
public abstract class usrTableSelection : IBqlField
{
}
#endregion
#region Selector
[PXDBInt]
[PXUIField(DisplayName = "Table Selector")]
[MyCustomSelector(
typeof(APRegisterExt.usrTableSelection),
typeof(TableA.id),typeof(TableA.description),
typeof(TableB.id), typeof(TableB.description),
typeof(PX.Objects.AR.Customer.bAccountID),
typeof(PX.Objects.AR.Customer.acctName))]
public virtual int? UsrTableSelector { get; set; }
public abstract class usrTableSelector : IBqlField
{
}
#endregion
4- Also, you should not forget to set the visibility on your tables fields. I'm referring to the tables (DACs
) that you want to display in the selector. Let say that you want to display TableA
, TableB
or TableC
depending on your drop down, you need to set the visibility on the fields that you are going to use in the selector.
Here's the implementation of one of the tables that I used during my tests:
[Serializable]
public class TableA : IBqlTable
{
#region Id
[PXDBInt(IsKey = true)]
[PXUIField(DisplayName = "Id")]
public int? Id { get; set; }
public class id : IBqlField { }
#endregion
#region Description
[PXDBString(60, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Description", Visibility = PXUIVisibility.SelectorVisible)]
public string Description { get; set; }
public class description : IBqlField { }
#endregion
#region InfoA
[PXDBString(60, IsUnicode = true, InputMask = "")]
[PXUIField(DisplayName = "Info A", Visibility = PXUIVisibility.SelectorVisible)]
public string InfoA { get; set; }
public class infoA : IBqlField { }
#endregion
}
By setting the visibility to SelectorVisible
, the field will be displayed automatically in the PXSelector.
5- Finally, you need to set CommitChanges
to True
on your dropdown and set AutoRefresh
to True
on your form field. Here's an example:
<px:PXDropDown runat="server" ID="CstPXDropDown1" DataField="UsrTableSelection" CommitChanges="True" />
<px:PXSelector runat="server" ID="CstPXSelector2" DataField="UsrTableSelector" AutoRefresh="True" />