How to add a custom Mass Action button to a GI in Acumatica - button

Using Build 21.210.0030
I’m a bit of a ‘noob’ to Acumatica dev and I have a question concerning toolbar buttons on a Generic Inquiry (GI) with the intention of performing a Mass Action. The following PXAction works on the Vendor form (../Main?ScreenId=AP303000&AcctCD=AASERVICES):
public class VendorMaint_Extension : PXGraphExtension<VendorMaint>
{
public SelectFrom<PX.Objects.CR.BAccount>.View suppliers;
#region buttons
public PXAction<PX.Objects.CR.BAccount> myButton;
[PXButton(CommitChanges = true)]
[PXUIField(DisplayName = "Verify Now", IsDirty = true)]
public virtual IEnumerable MyButton(PXAdapter adapter)
{
BAccount supplier = suppliers.Current;
PX.Objects.CR.BAccountExt bAccountExt = PXCache<BAccount>.GetExtension<PX.Objects.CR.BAccountExt>(supplier);
// do my stuff...
//...
//...
return adapter.Get();
}
#endregion buttons
//...
//...
My GI is a filtered copy of AP-Vendors (AP3030PL) but I can’t get my button to display in the list of available Mass Actions. I’ve tried adding the following in the class (above)
public override void Initialize()
{
base.Initialize();
myButton.IsMass = true;
Base.action.AddMenuAction(this.myButton);
}
and I’ve tried many variations of this Initialize method but none seem to make a difference. I've also tried to implement the answers provided in these previous questions (to no avail):
How to add action button in Inquiry page? and
Add Custom action to GI Mass Actions dropdown
I think part of my issue is that I don't fully understand whether to use BAccount, VendorR and/or Vendor yet.
I fully accept that I might be doing it all wrong so any and all help will be gratefully appreciated.
Thanks

Turns out it was relatively straight-forward, very similar to the way processing forms work. I had to change the button from a PXButton to a PXProcessButton in my VendorMaint_Extension class and move the code (that does the actual work) into a static method used by the PXLongOperation e.g.
```
[PXProcessButton(CommitChanges = true)]
[PXUIField(DisplayName = "Verify Now", IsDirty = true)]
public virtual IEnumerable MyButton(PXAdapter adapter)
{
bool isMassProcess = adapter.MassProcess;
List<BAccount> vendorList = new List<BAccount>();
foreach (BAccount bAcc in adapter.Get<BAccount>())
{
PX.Objects.CR.BAccountExt bAccountExt = PXCache<BAccount>.GetExtension<PX.Objects.CR.BAccountExt>(bAcc);
if (bAccountExt.UsrIsSomething == true)
{
vendorList.Add(bAcc);
}
}
// trigger the Save action to save changes in the database.
Base.Save.Press();
PXLongOperation.StartOperation(this, delegate ()
{
DoMyStuff(vendorList, isMassProcess);
});
return vendorList;
}
```

Related

Xamarin.Forms activate/deactivate toolbar items not working

I have a Xamarin.Form MainPage:ContentPage with a ToolbarItems Bar on top. The toolbar items are bound to my ViewModel like so:
<ToolbarItem Text="Sync" Command="{Binding ReloadCommand}" >
</ToolbarItem>
The availability of the Item depends on some logic:
private bool canReloadExecute(object arg)
{
bool result = (!IsReloading && (App.GetPersistentSetting("DeviceID") != "") && (App.GetPersistentSetting("BuildingID") != ""));
return result;
}
There is a separate dialog controlling the DeviceID and BuildingID on a different settings page. Once any of those ids is entered it is persistently stored away
App.SetPersistentSetting("DeviceID",value);
Problem is, that the menu items don't change their appearance once my code uses popAsync() to return to the Main page. I need to restart my app to see the changes. According to the debugger, canReloadExecute isn't called. Why this?
What I tried to work around this issue is to force a refresh in the MainPage's OnAppearing method like this:
public void RefreshToolbarItems()
{
TestApp.ViewModels.MainViewModel mvm = (TestApp.ViewModels.MainViewModel)BindingContext;
mvm.RefreshToolbarItems();
}
... and in the ViewModel:
public void RefreshToolbarItems()
{
OnPropertyChanged("BuildingScanCommand");
OnPropertyChanged("ReloadCommand");
}
but this code runs through but changes nothing, while the Debugger shows that the routine is indeed firing the events, they seem to go nowhere.
Any ideas how I can get my menu going?
Edit 1: "Show command initalization"
I am not shre what specifically you mean, but here is the whole code dealing with the command:
private ICommand _reloadCommand;
public ICommand ReloadCommand => _reloadCommand ?? (_reloadCommand = new Command(ExecuteReloadCommand, canReloadExecute));
private bool _isReloading = false;
public bool IsReloading
{
get => _isReloading;
set
{
_isReloading = value;
((Command)_reloadCommand).ChangeCanExecute();
OnPropertyChanged(nameof(ReloadCommand));
}
}
private bool canReloadExecute(object arg)
{
bool result = (!IsReloading && (App.GetPersistentSetting("DeviceID") != "") && (App.GetPersistentSetting("BuildingID") != ""));
return result;
}
private async void ExecuteReloadCommand(object obj)
{
IsReloading = true;
// Some code ...
IsReloading = false;
}
The goal is to disable the command, if either the command handler is already running, or if the configuration of DeviceID and/or BuildingId hasn't been done yet.
The enable/disable does almost work, if I set the DeviceId and BuildingId, and restart the app, the command is properly enabled or disabled. It doesn't work, however, if I set the Ids in a sub-page and return to the main page.
meanwhile I came to the conclusion, that firing onPropertyChange obviously doesn't make the command check its canReloadExecute. So the question is, how do I trigger this?
I finally solved the issue myself, this code works nicely for me:
public void RefreshToolbarItems()
{
((Command)BuildingScanCommand).ChangeCanExecute();
((Command)ReloadCommand).ChangeCanExecute();
}

Enabling and disabling specific buttons in and Enum in C#

i have this enum called ScoreType.
public enum ScoreType {
Ones, Twos, Threes, Fours, Fives, Sixes,
SubTotal, BonusFor63Plus, SectionATotal,
ThreeOfAKind, FourOfAKind, FullHouse,
SmallStraight, LargeStraight, Chance, Yahtzee,
YahtzeeBonus, SectionBTotal, GrandTotal
}
I would like to in the EnableScoreButton method to enable the specified button corresponding to the ScoreType parameter of 'combo'.
public void EnableScoreButton(ScoreType combo) {
//SOMTHING.Enabled = true;
}
Could you please show me how to do this?

How to pass argument from one form to another form in ax 2012

Table has one date field. I have two form name as formA and formB ,formA has textbox and button. formB has grid with date field.
So my question is if I enter date in textbox and clicked the button of formA, entered date should be assign in grid of formB. I added table datasource of both forms. Please help me out on this.
Although behavior described by you seems to be not so standard in terms of AX, I would suggest you to use dialog form as a FormA (rather than regular form). That way you respect best practices and desired behavior is achieved easier.
Create class extending RunBase class with date field:
class FormADialog extends RunBase
{
DialogField fieldDate;
TransDate transDate;
}
Here is how we construct form controls:
protected Object Dialog()
{
Dialog dialog = super();
fieldDate = dialog.addField(extendedTypeStr(TransDate), 'Date');
return dialog;
}
The following method will retrieve values from Dialog:
public boolean getFromDialog()
{
transDate = fieldDate.value();
return super();
}
Processing logic goes here:
public void run()
{
FormBTable formBTable;
ttsbegin;
select firstOnly forUpdate formBTable;
formBTable.Date = transDate;
formBTable.write();
ttscommit;
}
The only missing thing is entry point for dialog class (represents FormA):
public static void main(Args _args)
{
FormADialog formADialog = new FormADialog();
FormDataSource formDataSource;
if (formADialog.prompt())
{
formADialog.run();
// FormB should contain menu item for dialog class for the following code
if (args && args.record() && args.record().dataSource())
{
formDataSource = args.record().dataSource();
formDataSource.research();
}
}
}
Now clicking on dialog button will update grid.
If you insist on use of approach with two regular forms. I will think of linkActive() method at the datasource of the second form. Take a look at
Tutorial Form Dynalink. A record change in the parent form notifies the child form, making it call the linkActive method which in turn calls the executeQuery method at the child table datasource.
Another approach could be as follows.
For passing parameters from one form to another a special class Args is usually used.
Initiator form prepares data for transfer within clicked() method of button control:
void clicked()
{
Args args;
FormRun formRun;
args = new Args();
args.parm(dateField.text());
args.name(formStr(FormB));
formRun = classFactory.formRunClass(args);
formRun.init();
formRun.run();
formRun.wait();
super();
}
Receiving endpoint should listen at init() method of FormB:
public void init()
{
Date passedValue;
super();
// check presence
if (element.args())
{
passedValue = str2Date(element.args().parm(), 123);
}
}
Take a look at axaptapedia.com article to see how we can pass complex set of parameters within custom made class.

Xamarin.Forms - MKMapView iOS Render

I tried using Xamarin.Forms.Maps, and it is missing many features, so I decided to make an iOS ViewRenderer with the MKMapView and adding custom pin images and such, but I am not sure how to make a ViewRenderer and how MKMapView works. Can someone be kind enough to show me how it works and give me a small quick example of just showing the map.
I just want to make a custom render for ios that will show MKMapView, the rest i can probably figure out, but I cant even figure out how to make it show from the viewrenderer.
Simple example on how to build your Custom ViewRenderer
in your PCL project create something that inehrits from view:
public class CustomMap: View
{
public static readonly BindableProperty PinsItemsSourceProperty = BindableProperty.Create ("PinsItemsSource ", typeof(IEnumerable), typeof(CustomMap), null, BindingMode.OneWay, null, null, null, null);
public IEnumerable PinsItemsSource {
get {
return (IEnumerable)base.GetValue (CustomMap.PinsItemsSourceProperty );
}
set {
base.SetValue (CustomMap.PinsItemsSourceProperty , value);
}
}
}
Then on your IOS create your custom renderer for that view like so:
[assembly: ExportRenderer(typeof(CustomMap), typeof(CustomMapRenderer ))]
namespace Xamarin.Forms.Labs.iOS.Controls
{
public class CustomMapRenderer : ViewRenderer<CustomMap,MKMapView >
{
protected override void OnElementChanged (ElementChangedEventArgs<CustomMap> e)
{
base.OnElementChanged (e);
var mapView = new MKMapView (this.Bounds);
mapView.AutoresizingMask = UIViewAutoresizing.FlexibleDimensions;
foreach(item in e.NewElement.PinsItemsSource )
{
//add the points
var annotation = new BasicMapAnnotation (new CLLocationCoordinate2D(x,y), "something", "something");
mapView.AddAnnotation(annotation);
}
base.SetNativeControl(mapView);
}
}
ps: i wrote this code on the fly from my head and i didn't tested but it should help you get going

how to update Visual Studio UI when using DynamicItemStart inside a vsix package

I'm implementing a DynamicItemStart button inside a Menu Controller. I'm loading the dynamic items for this button when Visual Studio starts. Everything is loaded correctly so the initialize method is called an I see all the new items in this Dynamic button. After the package is completely loaded I want to add more items to this Dynamic button, but since the package is already loaded the initialize method is not called again and I cannot see the new items in this Dynamic button. I only see the ones that were loaded when VS started.
Is there any way that I can force the update of this Dynamic button so it shows the new items?. I want to be able to update the VS UI after I added more items but outside the Initialize method.
The implementation I did is very similar to the one showed on this msdn example:
http://msdn.microsoft.com/en-us/library/bb166492.aspx
Does anyone know if an Update of the UI can be done by demand?
Any hints are greatly appreciated.
I finally got this working. The main thing is the implementation of a derived class of OleMenuCommand that implements a new constructor with a Predicate. This predicate is used to check if a new command is a match within the DynamicItemStart button.
public class DynamicItemMenuCommand : OleMenuCommand
{
private Predicate<int> matches;
public DynamicItemMenuCommand(CommandID rootId, Predicate<int> matches, EventHandler invokeHandler, EventHandler beforeQueryStatusHandler)
: base(invokeHandler, null, beforeQueryStatusHandler, rootId)
{
if (matches == null)
{
throw new ArgumentNullException("Matches predicate cannot be null.");
}
this.matches = matches;
}
public override bool DynamicItemMatch(int cmdId)
{
if (this.matches(cmdId))
{
this.MatchedCommandId = cmdId;
return true;
}
this.MatchedCommandId = 0;
return false;
}
}
The above class should be used when adding the commands on execution time. Here's the code that creates the commands
public class ListMenu
{
private int _baselistID = (int)PkgCmdIDList.cmdidMRUList;
private List<IVsDataExplorerConnection> _connectionsList;
public ListMenu(ref OleMenuCommandService mcs)
{
InitMRUMenu(ref mcs);
}
internal void InitMRUMenu(ref OleMenuCommandService mcs)
{
if (mcs != null)
{
//_baselistID has the guid value of the DynamicStartItem
CommandID dynamicItemRootId = new CommandID(GuidList.guidIDEToolbarCmdSet, _baselistID);
DynamicItemMenuCommand dynamicMenuCommand = new DynamicItemMenuCommand(dynamicItemRootId, isValidDynamicItem, OnInvokedDynamicItem, OnBeforeQueryStatusDynamicItem);
mcs.AddCommand(dynamicMenuCommand);
}
}
private bool IsValidDynamicItem(int commandId)
{
return ((commandId - _baselistID) < connectionsCount); // here is the place to put the criteria to add a new command to the dynamic button
}
private void OnInvokedDynamicItem(object sender, EventArgs args)
{
DynamicItemMenuCommand invokedCommand = (DynamicItemMenuCommand)sender;
if (null != invokedCommand)
{
.....
}
}
private void OnBeforeQueryStatusDynamicItem(object sender, EventArgs args)
{
DynamicItemMenuCommand matchedCommand = (DynamicItemMenuCommand)sender;
bool isRootItem = (matchedCommand.MatchedCommandId == 0);
matchedCommand.Enabled = true;
matchedCommand.Visible = true;
int indexForDisplay = (isRootItem ? 0 : (matchedCommand.MatchedCommandId - _baselistID));
matchedCommand.Text = "Text for the command";
matchedCommand.MatchedCommandId = 0;
}
}
I had to review a lot of documentation since it was not very clear how the commands can be added on execution time. So I hope this save some time whoever has to implement anything similar.
The missing piece for me was figuring out how to control the addition of new items.
It took me some time to figure out that the matches predicate (the IsValidDynamicItem method in the sample) controls how many items get added - as long as it returns true, the OnBeforeQueryStatusDynamicItem gets invoked and can set the details (Enabled/Visible/Checked/Text etc.) of the match to be added to the menu.

Resources