Dynamics AX 2009: How to programmatically allowEdit on Checkbox control - axapta

Essentially, this is what I'm faced with:
I want to modify the InventTrans form
By default, it has the entire InventTrans datasource set to AllowEdit = No
I want to enable editing on ONE new Enum field (NoYes type)
Should I set the InventTrans datasource to AllowEdit = Yes and then painfully change 40+ fields in the datasource to be AllowEdit = No, OR is there a way to programmatically iterate through the fields of the datasource and set this property by name? (Please say there is, or an equally easy way to do this!)
Thanks in advance!

This is how I would try to disable editing to all fields:
DictTable dictTable;
DictField dictField;
int fldCnt;
;
dictTable = new DictTable(tablenum(InventTrans));
for (fldCnt = 1; fldCnt <= dictTable.fieldCnt() ; fldCnt++)
{
dictField = new DictField(tablenum(InventTrans), dictTable.fieldCnt2Id(fldCnt));
info(strfmt("%1", dictField.id(),dictField.name()));
InventTrans_DS.object(dictField.id()).allowEdit(false);
}
EDIT: Better approach to iterate through form's DS'es fields only:
DictTable dictTable;
DictField dictField;
int fldCnt;
QueryBuildFieldList qBFL;
;
qBFL = InventTrans_DS.query().dataSourceTable(tablenum(InventTrans)).fields();
for (fldCnt = 1; fldCnt <= qBFL.fieldCount() ; fldCnt++)
{
dictField = new DictField(tablenum(InventTrans), qBFL.field(fldCnt));
info(strfmt("%1 %2 ", dictField.id(),dictField.name()));
if(InventTrans_DS.object(qBFL.field(fldCnt))) //exception recVersion for example
{
InventTrans_DS.object(qBFL.field(fldCnt)).allowEdit(false);
}
}

I have a scenario in which I want to allow editing of ItemID in the InventJournalTrans form, based on an enum value in ANOTHER form. Is this possible?
Can args() class(parm method) be used to fetch the value of the checkbox? along with on the below condition in the active()?
My codes:
public int active()
{
int ret;
;
ret = super();
if([datasource table name].[Column 1 field name] == [Column1 value to
deactivate Column 3])
{
[datasource table name]_ds.object(fieldNum([datasource table name],
[Column 1 field name])).allowEdit(false);
}
else
{
[datasource table name]_ds.object(fieldNum([datasource table name],
[Column 1 field name])).allowEdit(true);
}
return ret;
}

Related

Loop through grid columns in runtime in AX 2012

I want to loop through columns(fields) in grid control in AX 2012 form. I have this logic to loop through fields :
static void Job1(Args _args)
{
SysDictTable dictTable = new SysDictTable(tableNum(PurchLine));
SysDictField dictField;
TreeNode treeNode;
FieldId fieldId = dictTable.fieldNext(0);
while (fieldId)
{
dictField = dictTable.fieldObject(fieldId);
if (dictField.isSql() && !dictField.isSystem())
{
treeNode = dictField.treeNode();
info(strFmt("%1 | %2 | %3",
dictField.name(), // Field name
treeNode.AOTgetProperty("Label"), // Label id
SysLabel::labelId2String(treeNode.AOTgetProperty("Label")))); // Label string
}
fieldId = dictTable.fieldNext(fieldId);
}
}
This loop through table, I need similar logic to loop through grid fields but in RUNTIME.
For example if grid data source has 5 columns and 3 are removed in UI, i want to loop just through these 2 that are left in the grid.
So my question is how to get grid fields in runtime( not from datasource table) ?
The below assumes your grid is named "GridOverview". You call it like:
::outputGridControls(element) where element is your form.
public static void outputGridControls(FormRun _formRun)
{
int i;
FormGridControl formGridControl;
FormControl formControl;
formGridControl = _formRun.control(_formRun.controlId(identifierStr(GridOverview)));
if (formGridControl)
{
for (i=1; i<=formGridControl.controlCount(); i++)
{
formControl = formGridControl.controlNum(i);
if (formControl && formControl.visible())
{
info(strFmt("%1 (%2)", formControl.name(), formControl.labelText()));
}
}
}
}
What you're doing above is reflecting on the AOT table, but you need to be looking at the FormRun and not the actual table or even the DataSource.

How to find all tables using a defined EDT?

How does one create a job which finds all tables containing a particular extended data type?
I found this JOB, but it gives me an error: https://fredshen.wordpress.com/2006/02/05/find-out-tables-containing-specific-edt/
Use the Cross Reference Tool.
It will show code uses as well.
try this:
static void findEdtinTable(Args _args)
{
treeNode childNode;
treeNode fields;
treenodeIterator it, itFld;
str properties;
str table;
str field;
str extendedDataType;
str searchType = "PurchInternalInvoiceId"; // EDT
int x;
treeNode t = TreeNode::findNode('\\Data Dictionary\\Tables');
it = t.AOTiterator();
childNode= it.next();
while (childNode)
{
Table = childNode.treeNodeName();
itFld = t.AOTfindChild(childNode.treeNodeName()).AOTfindChild("Fields").AOTiterator();
fields = itFld.next();
while (fields)
{
field = fields.treeNodeName();
properties = fields.AOTgetProperties();
extendedDataType = findProperty(properties, "ExtendedDataType");
if (extendedDataType == searchType)
{
info(strfmt("%1 / %2 – ExtendedDataType: %3", table, field, extendedDataType));
}
fields = itFld.next();
}
childNode= it.next();
}
}

X++ passing current selected records in a form for your report

I am trying to make this question sound as clear as possible.
Basically, I have created a report, and it now exists as a menuitem button so that the report can run off the form.
What I would like to do, is be able to multi-select records, then when I click on my button to run my report, the current selected records are passed into the dialog form (filter screen) that appears.
I have tried to do this using the same methods as with the SaleLinesEdit form, but had no success.
If anyone could point me in the right direction I would greatly appreciate it.
Take a look at Axaptapedia passing values between forms. This should help you. You will probably have to modify your report to use a form for the dialog rather than using the base dialog methods of the report Here is a good place to start with that!
Just wanted to add this
You can use the MuliSelectionHelper class to do this very simply:
MultiSelectionHelper selection = MultiSelectionHelper::createFromCaller(_args.caller());
MyTable myTable = selection.getFirst();
while (myTable)
{
//do something
myTable = selection.getNext();
}
Here is the resolution I used for this issue;
Two methods on the report so that when fields are multi-selected on forms, the values are passed to the filter dialog;
private void setQueryRange(Common _common)
{
FormDataSource fds;
LogisticsControlTable logisticsTable;
QueryBuildDataSource qbdsLogisticsTable;
QueryBuildRange qbrLogisticsId;
str rangeLogId;
set logIdSet = new Set(Types::String);
str addRange(str _range, str _value, QueryBuildDataSource _qbds, int _fieldNum, Set _set = null)
{
str ret = _range;
QueryBuildRange qbr;
;
if(_set && _set.in(_Value))
{
return ret;
}
if(strLen(ret) + strLen(_value) + 1 > 255)
{
qbr = _qbds.addRange(_fieldNum);
qbr.value(ret);
ret = '';
}
if(ret)
{
ret += ',';
}
if(_set)
{
_set.add(_value);
}
ret += _value;
return ret;
}
;
switch(_common.TableId)
{
case tableNum(LogisticsControlTable):
qbdsLogisticsTable = element.query().dataSourceTable(tableNum(LogisticsControlTable));
qbrLogisticsId = qbdsLogisticsTable.addRange(fieldNum(LogisticsControlTable, LogisticsId));
fds = _common.dataSource();
for(logisticsTable = fds.getFirst(true) ? fds.getFirst(true) : _common;
logisticsTable;
logisticsTable = fds.getNext())
{
rangeLogId = addrange(rangeLogId, logisticsTable.LogisticsId, qbdsLogisticsTable, fieldNum(LogisticsControlTable, LogisticsId),logIdSet);
}
qbrLogisticsId.value(rangeLogId);
break;
}
}
// This set the query and gets the values passing them to the range i.e. "SO0001, SO0002, SO000£...
The second methods is as follows;
private void setQueryEnableDS()
{
Query queryLocal = element.query();
;
}
Also on the init method this is required;
public void init()
{
;
super();
if(element.args() && element.args().dataset())
{
this.setQueryRange(element.args().record());
}
}
Hope this helps in the future for anyone else who has the issue I had.

how to read each value of a column in a table

Using x++ how to create a job to read each value of a column in a table in Microsoft dynamics AX 2009?
This code will display all the column values for a record.
static void Job1(Args _args)
{
DictTable dictTable = new DictTable(tableNum(CustTable));
DictField dictField;
int counter, fieldId;
CustTable custTable;
anytype value;
select firstonly custTable;
for (counter = 1; counter <= dictTable.fieldCnt(); counter++)
{
fieldId = dictTable.fieldCnt2Id(counter);
dictField = new DictField(tableNum(CustTable), fieldId);
if (!dictField.isSystem())
{
value = custTable.(fieldId);
if(value)
{
info(strFmt('%1 = %2',
dictField.label(),
any2str(value)));
}
}
}
}
For getting all the values for a specific column, please use Carlos Heuberger's code.
One possibility: in the AOT (Ctrl-D) right-click on Jobs and select New Job. In the new window enter something like (using the correct table and column name you want to read):
static void Job()
{
YourTable yourTable;
;
while select TheColumn from yourTable
{
// process yourTable.TheColumn
info(strFmt("value: %1", yourTable.TheColumn));
}
}
but thera are some other ways: Select Statements
Just a slight mod, took out any2str to make my table work:
strFmt('%1 = %2 \r\n', dictField.label(), value);

If I fill a GridView with anonymous objects, how can i get their properties?

I have a GridView what I fill through a LINQ expression.
Something like this:
GridView1.DataSource = from c in customers, o in c.Orders,
total = o.Total where total >= 2000 select new {id = c.CustomerID,
order = o.OrderID, total = total};
And in its RowCreated method I try to get a property, for example the id, but it has no a known type:
object element = e.Row.DataItem;
int id = element.id; // It's bad!!!!!!
How can I do?
Thanks!!
Name your type!
public class GridType
{
public int Id {get; set:} . . etc
}
then in linq,
. . . select new GridType {...etc}
Then in the RowCreated method, cast the dataitem to GridType, and you can ccess it's properties.
Otherwise your looking for duck typeing which C# doesn't do.
You need to use reflection.
Type t = element.GetType();
int id = 0;
foreach (PropertyInfo p in t.GetProperties())
{
// Not very nice but finds an integer property called "id"
if (p.PropertyType == typeof(int) && p.Name == "id")
{
id = (int)p.GetValue(element, null);
}
}
Using Linq:
Type t = element.GetType();
int id = 0;
var pt = new List<PropertyInfo>();
pt.AddRange(t.GetProperties());
id = (int)pt.Where(p => p.PropertyType == typeof(int) && p.Name == "id").First().GetValue(element, null);
Not sure it reads any better though, especially as Type.GetProperties returns an array which has to be converted to a List to get at the Linq methods.
This is the cost you have to pay if you want to use anonymous objects : you loose the strong typing when you leave the scope where your object is declared. I'd recommend to explicitly declare your type, unless you want to play with DataBinder.Eval...

Resources