August 24, 2011 at 12:00
filed under Dynamics AX
Tagged 2012, Batch, Dynamics AX, SysOperation
Hi everyone.
This is the third and final part in my series of posts about SysOperation (at least for now). You can find part 1 here and part 2 here.
I will demonstrate how to override methods on the dialog (in this case modified()), and how to read and set properties of controls.
For the sake of this demo, we will add a checkbox to the dialog that will allow us to set the enabled property of the date control.
It should look like this:
We will need to modify the data contract so a checkbox is displayed on the dialog that we can use to enable or disable the date control.
Add this variable to the class declaration of the KlForCustTesterDataContract class:
Then add this method to that same data contract
There’s nothing new here, we already did all of this in part 1
We will extend the SysOperationAutomaticUIBuilder class so we can override methods and properties of controls on our dialog.
First, create a new class, KlForCustTesterUIBuilder:
Things we will need in this class are:
So we add these variables to the class declaration:
We will first write the method that will override the modified of the checkbox control. Simply add a new method to the KlForCustTesterUIBuilder class:
The code above sets the enabled method on the dialogFieldTransDate object based on the value property of dialogFieldAllowModifyDate object, or alternatively, the _checkBoxControl variable.
As you may remember, we declared the DialogField variables in the class declaration. Of course we will still have to initialize these variables , and that’s what we’ll do when overriding the postBuild method.
Next, we need to override the postBuild method on our KlForCustTesterUIBuilder class. This method will be called after the dialog is created, so it is a good place to put our logic.
Override the method:
Next, let’s add some code to this method, starting with the code that retrieves the data contract object, which is pretty easy:
Next, we retrieve the DialogField objects:
In the code above, the bindInfo() method returns an object of type SysOperationUIBindInfo. This contains information about which dialog controls the data members are bound to. By providing a reference to the parmTransDate and parmAllowModifyDate member when calling the getDialogField() method, we get the dialog control that is associated with each member.
Next, we will register the method we want to override:
As you can see, we can use the registerOverrideMethod() method to override methods on dialog. This is a huge improvement over overriding methods on dialogs in 2009. We simply point to the method we want to override (FormCheckBoxControl.modified) and the method the needs to be executed (KlForCustTesterUIBuilder.allowModifyDateModified).
Finally, we initialize the value of the enabled property, and the complete method will look like this:
Now, we’ve created the UIBuilder class, but we still have to link it to our data contract. That’s what the SysOperationContractProcessingAttribute attribute is for.
To link the UIBuilder class to the data contract, open the classDeclaration method of the KlForCustTesterDataContract class, and add the SysOperationContractProcessingAttribute:
But wait (you already know what I’m going to say right), first click the Generate Incremental CIL button to generate CIL.
Right click the KlForCustTesterServiceController menu item we created on day 2, and choose open. You should see this dialog:
When you check the checkbox, you should see that the date field is enabled.
Download the XPO for part 3 here.
That concludes my blog posts about SysOperation, I hope you like it, and I’m looking forward to your feedback.
Have fun making batches!
Kenny Saelen
on August 25, 2011 at 01:18
Nice post !
I’ve made it past part 1 and 2 because I had seen this when creating a previous operation, but this one is new :-)
I wandered how it was done, so now I know :-)
greets,
K
DAX
on October 5, 2011 at 16:08
Hi!
Yesterday I had asked you 2 questions, I am elaborating one question here in point 1.
1: In runBase we can add Batch jobs and Batch tasks;We can select class name in the form by overriding some methods “cangobatchjournal”,”description” etc.. How we are going to do this in Business Operations Framework.
2:If we have a scenario like the same logic we have to execute for
a) inputs from the UI
b) for batch which will run in background taking the parameters from some table
3: How we are going to add “Default” button on the UI which will reset the values to default ?
Is “parmShowDialog” approach can be used ?
Class Sysoperationssevicecontroller/startoperations will call to parmshowdialog.
Thanks,
Bhasker
Sandip
on October 27, 2011 at 08:26
Hi,
I have a requirement for SSRS dialog event as described by you in this article. Have developed my UIbuilder and contract class same as described. But facing a strange issue in postBuild() method of UIBuilder class. The dialog field is always getting a null value through bindInfo() method and throwing stack trace error when report dialog is opened.
Following is the code snippet:
totalByPostingProfile = this.bindInfo().getDialogField(rdpContract, methodStr(CustAccountStatementCurrContract_FR, parmTotalByPostingfrofile));
here variable totalByPostingProfile not been initialised and getting a null value.
Can you please provide any suggestion ?
Klaas Deforche
on October 27, 2011 at 10:04
Hi, Sandip,
That’s strange. Did you call the super() method?
Also, check if the parmTotalByPostingfrofile method is declared public.
If you run the SysOperation withoud the UIBuilder, does everything work then? Are the fields on the dialog?
Can you post the complete code of the method?
If all else fails, do a compile forward on your classes, remove your auc file, restart your aos and compile CIL.
I’ve noticed that some errors are due to AX behaving odd.
Klaas Deforche
on October 27, 2011 at 10:31
Hi DAX,
1. You can still do the “multithreading”. Check the class PurchFinalizeService for an example. I didn’t try it myself yet, on reason is that I don’t really like how they solved MS solved it. They still use RunBaseBatch classes for the tasks…
2. In that case I think I would create two controller classes, one that takes input from the dialog, and one that reads the table and fills the datacontract. You can reuse the service so this shouldn’t take long.
3. I’m affraid I can’t answer this one, I couldn’t find the default button option either. Normally when you press the default button, the initParmDefault method should be called.
Check the SysOperationController class, methods initParmDefault and initializeParametersInternal. My guess is that it has something to do with contracts that implement SysOperationInitializable. But you still need a button to call the initParmDefault method… I’ll have to research that myself…
Arshad Kalam
on November 18, 2011 at 19:46
Great Post!!!!!.
Thank you so much….
Kumar
on June 1, 2012 at 22:21
Hi,
Thanks for the great post !
I have a scenario where i need to have the default dialogField returned by the query(‘Customer account’ in your example) enabled/disabled depending on a checkbox.
Basically, the Batch Job is supposed to run on different criterion(based on different ranges for the query) and the checkbox is merely intended to either use a base criteria or a any criteria(which is there by default).
So, i tried to achieve the objective by following the exact procedure as shown here, only i’m trying to get the dialogField from the parmQuery :
dialogFieldQuery = this.bindInfo().getDialogField(KlForCustTesterDataContract, methodstr(KlForCustTesterDataContract, parmQuery));
and subsequently enable/disable it based on the checkbox value.
Unfortunately, it didn’t work for me and threw a ‘Dialog field object not initialized’ on the registerOverideMethod().
Any insights ??
Klaas Deforche
on June 6, 2012 at 14:44
Hi Kumar,
I don’t that that’ll work, because the parmQuery is not mapped to a dialogfield. The dialogfields you see are because you added a range on the query.
I think you’ll have to update or add a query range instead.
If the checkbox is on, you add a range on the query (and set it as locked so it can’t be edited?). If the checkbox is off, allow users to specify their own range when the click on the select button.
Does that make sense in your scenario?
Hope it helps.
Kumar
on July 3, 2012 at 00:42
Yup, that makes sense !
Thanks !!
Søren
on December 13, 2012 at 10:15
Hi, great tutorial.
Is it possible to set any of your parms to be mandatory??
E.g the Name field, so the user cannot continue before filling in something.
It is easy enough to validate after they click ok, but a bit late in the flow I believe.
/Søren
Klaas Deforche
on December 13, 2012 at 14:14
Hi Søren,
Yes it is possible. One way you can do it that I didn’t describe (because I didn’t know) is to implement the SysOperationValidatable interface on your data contract.
Then implement the valdiate method on your data contract and put validation code there.
Same for initializing parms, you can implement the SysOperationInitializable interface.
Kishore
on March 19, 2013 at 22:58
Good JOb!!
It really hepful to create a batch jobs.
Christobaal
on May 16, 2013 at 19:39
Hello Klass (btw ‘Klass’ is a great name for an OO dev ^^)
I just wanted to say a big ‘Thanks !’ for your tutorial.
Even 2 years later, it’s really usefull ;)
Keep up the good job !
Cheers !
JC
Klaas Deforche
on May 16, 2013 at 20:19
It is fitting isn’t it :). Thanks for the kind words, I’m glad I could help.
Beat Pallagi
on June 18, 2013 at 11:06
Hi Klaas,
thnx 4 sharing this.
MadsenSenior
on September 10, 2013 at 06:57
Hi Klaas, very nice post, I have done the programming and get 2 entries in the batchjob list, every time i run it, but my batch jobs is being repeted, when it has finished a new entry in the batchjob list is created with a new start time, what can I have done wrong?
Søren Andersen
on January 28, 2014 at 15:10
Hi, is it possible to hide the General tab??
If I only want the batch tab..
Best regards
Søren Andersen
Klaas Deforche
on January 31, 2014 at 11:24
Hi Søren,
I’ve tried but failed so far. I will look into it over the weekend.
Options I’m thinking of:
– using an other form template on the controleler
– modifying the UI builder to hide the general tab (it works but you have to activate the batch tab afterwards)
Best regards,
Klaas.
Albert Akuamoah
on April 15, 2014 at 17:06
Hi Søren,
I just tried this and it worked as a work around. I simply activate the batch Tab. I have a class which extends SysOperationServiceController so I override the dialogPostRun and selected the batch tab.
In SysOperationController dialogPOstRun, MSFT sets the active tab to be the General tab. You can leverage that code if you want a systemwide effect. (I wouldn’t recommend it though)
protected void dialogPostRun()
{
sysOperationDialog sysOperationDialog;
DialogTabPage batchTab;
FormRun fr;
super();
sysOperationDialog = this.dialog() as SysOperationDialog;
fr = sysOperationDialog.formRun();
batchTab = sysOperationDialog.batchDialogTabPage();
fr.selectControl(batchTab.control());
}
By the was Klaas, You do a wonderful job of sharing your AX knowledge. Thanks.
Klaas Deforche
on April 17, 2014 at 23:18
Hi Albert, thank you for sharing your solution.
I’m sure this will come in very handy :).
Albert Ritmeester
on September 3, 2014 at 16:05
Thanks for the clear documentation!
I have one question: I want to override the lookupReference for a FormReferenceControl. I cannot get it working. Do you have any idea how to achieve this?
Thanks!
John Shine
on November 11, 2014 at 19:05
Are you aware of a control that will submit a job without the need for the UI (batch dialog). We wish to use sysOperation to fire off a batch job without user input if possible.
John Shine
on November 11, 2014 at 19:51
parmshowdialog(false)
Ashish
on June 20, 2015 at 22:36
getting error dialog object not intialized please help
Swapna
on June 26, 2015 at 16:00
Use this code in controller postRiun method to hide the general tab on the dialog. It worked for me.
this.dialog().dialogForm().tab().showTabs(false);
Preetham
on July 27, 2015 at 13:22
Hi,
How can I get query object initialized in post build the similar way as dialog field?
Thanks!
Arpit
on October 8, 2015 at 14:53
@Søren : to remove the general tab, simply remove the contract parameter from the service class method.
It worked for me.
I have one query for all of you, it will be very helpful if you guys suggest me.
my dialog takes a parameter as file from the local computer.
So I used FileNameOpen edt to define my parmMethod in contract class, so that I will get the browse option on my dialog. The same edt we used when we were using RunBaseBatch.
But when i try to open it, it doesnt show me browse button.
Anyone ???
John Hagler
on December 17, 2015 at 00:51
I’m running into an interesting scenario when using a template form. When I don’t override the SysOperationServiceController.templateForm() method and let the standard functions build the dialog UI, I get the dialog parameters put into a smaller section with scrollbars. One way I have attempted to get around this is to create a form and use it for the template form. This allows me to disallow scrollbars in the form so it displays correctly. The side effect is that the BatchInfo doesn’t recognize the batch checkbox. So I don’t seem able to send something to batch with a template form. This does work for the exact same class however if I let the standard UIBuilder handle the dialog. Any ideas what could be causing this?
DM
on December 22, 2015 at 13:53
Hey Arpit,
Controls are bound to using a data contract.
So use a data contract with one of the attribute as FileNameOpen.
To hide the general tab –
In controller’s dialog post run method i wrote below code –
protected void dialogPostRun()
{
sysOperationDialog sysOperationDialog;
FormTabControl tabControl;
FormRun formRun;
#define.generalTabControlName(‘Tab’)
super();
sysOperationDialog = this.dialog() as SysOperationDialog;
formRun = sysOperationDialog.formRun();
tabControl = formRun.design().controlName(#generalTabControlName);
tabControl.showTabs(false);
}
Give it a shot.
Michele
on July 29, 2016 at 20:46
Do you know how I can get the filenameopen option to work with the SysOperationFramework? I have a parm method in my contract class with FileNameOpen EDT but still not seeing the file browser button when running the service?
Andrew Xu
on February 24, 2017 at 20:05
Sandip,
You’ll need to use SRSReportDataContractUIBuilder instead of SysOperationAutomaticUIBuilder, if you’re working on a SSRS report.
Aleš
on March 9, 2017 at 12:30
Thanks for this nice article, very helpful for our Dynamics development
Juan Ramirez
on September 19, 2017 at 06:20
Hello,
In dynamics ax 2012 “The FormRun object could not be created”
code:
void GNP_VendInvoiceJourAddData_Clicked(FormButtonControl _formButtonControl)
{
DictTable dictTable;
Form formAddData;
FormBuildDataSource fbDatasource;
FormRun formRun;
Args args;
;
dictTable = new DictTable(tableNum(GNP_VendInvoiceJourAddData));
formAddData = new Form();
formAddData.name(“GNP_VendInvoiceJourAddData”);
fbDatasource = formAddData.addDataSource(dictTable.name());
fbDatasource.table(dictTable.id());
args = new Args();
args.object(formAddData);
formRun = classFactory.formRunClass(args);
formRun.init();
formRun.run();
formRun.detach();
}
stop code in “FormRun formRunClass(xArgs args)”
Please help.
Ash
on September 12, 2018 at 13:03
Thnx for this breakdown. I’m new to X++ (and programming in general) I tried out all of the posts and in Dynamics 365 I can confirm that most is still the same. However, the only thing that does not seem to work the same is the date. The field is empty. Even when I enable it, I have to select it manually.