Is it possible to display error in toolbar without using [PXProcessButton] and the delegate? I've overridden a Process Button in acumatica, but before it executes I have underlying codes to check a condition and fire an error if it find any.
There's not a lot of valid scenario where you have a PXProcessButton without a PXProcessing or PXFilteredProcessing data view. I would expect a PXButton to be used when there is no PXProcessing data view instead of a PXProcessButton.
With a PXProcessing view in the process screen you would do:
PXProcessing<DAC>.SetError(new PXException("Test));
There is no method that I know of that allows to directly set an error in the toolbar. You'll notice that these error are tied with a PXLongOperation. In the main toolbar you'll see the hourglass icon of the long operation and it can change to a success or error icon.
Process action does this but also Save action amongst others. Unless you require a long operation I would advise to avoid displaying error in the main toolbar because it's not a behavior found in the base Acumatica product.
That said you can replicate that functionality pretty much everywhere by throwing a PXExceptionfrom within a PXLongOperation inside an PXAction event handler like this:
public class SOOrderEntry_Extension : PXGraphExtension<SOOrderEntry>
{
public PXAction<SOOrder> test;
[PXUIField(DisplayName = "Test")]
[PXButton]
protected virtual IEnumerable Test(PXAdapter adapter)
{
PXLongOperation.StartOperation(Base, delegate {
throw new PXException("Test");
});
return adapter.Get();
}
}
Related
We are in to acumatica 20 r2 and when we publish the custom package, the default report menu print salesorder/quote option disappears.
We have custom reports which are added by overriding the initialize method of salesorderentry graph in my extension.
public override void Initialize()
{
base.Initialize();
base.Base.report.AddMenuAction(embroideryreport);
base.Base.report.AddMenuAction(embroiderysoreport);
base.Base.report.AddMenuAction(screenprintreport);
base.Base.report.AddMenuAction(screenprintsoreport);
}
I am not able to figure out the reason for missing report. I have upgraded the workflow to latest version and still having the issue.
UPDATE
I did not call base.Initialize() initially and since the default report is not coming, I thought it may be due to not invoking the base method.
I have tried bahaa-zantout suggestion and the base report is already tagged to the report menu and when I commented on the code in Initialize method for adding the report the default report appeared again under-report menu.
It looks like there is conflict in the workflow and I am not able to figure it out.
I have tried to add those report in the workflow action section and tagged them to Report and the entire report menu disappeared
Change you initialization method to....
public override void Initialize()
{
base.Base.report.AddMenuAction(embroideryreport);
base.Base.report.AddMenuAction(embroiderysoreport);
base.Base.report.AddMenuAction(screenprintreport);
base.Base.report.AddMenuAction(screenprintsoreport);
}
From Acumatica DEV documentation portal
You do not need to explicitly invoke the Initialize() method on the previous extension levels; these methods are called automatically. Invoking base.Initialize() makes no sense, because the base variable points to the base class, which is PXGraphExtension (not the base graph). The PXGraphExtension class defines Initialize() as an empty method.
You could attempt the following in attempt to restore the toolbar menu item.
Navigate to the Sales Order screen in the customization project
Go to the Actions
Locate the missing print options (ie. printSalesOrder) and place the Toolbar folder in the original folder in this case "Reports". If it doesn't work try moving to "Actions" and see if it appears.
See example screenshot.
I am not sure it is due to this statement or not but when I changed the following statement it fixed the issue
[PXButton(SpecialType = PXSpecialButtonType.ReportsFolder)]
to
[PXButton]
for Report action
public PXAction<SOOrder> embroideryreport;
[PXUIField(DisplayName = "Embroidery Production Report", MapEnableRights = PXCacheRights.Select)]
//[PXButton(SpecialType = PXSpecialButtonType.ReportsFolder)]
[PXButton]
I have created a new CREATE QUOTE button on Requisition screen that replace the standard button which located at Action menu. After trying to hide it on RQRequisition_RowSelected event, the button still appear and able to click when the requisition is on Pending Quote Status. Kindly need advice how to hide it.
Customized Requisition Screen
To hide or show an action button, you should redefine the Visible parameter of the PXUIField attribute for the button.
You can change attributes of an action button by using one of the following approaches:
Dynamically at run time, in the Initialize() method of the graph
extension
Statically, by overriding the action attributes in the
graph extension
To Hide an Action Button at Run Time
In the graph extension, add the following code.
public override void Initialize()
{
base.Initialize();
Base.MyAction.SetVisible(false);
}
In the added code, replace MyAction with the action name.
To Hide or Show an Action Button Statically
To override action attributes in a graph extension statically, you should declare both the graph member of the PXAction type and the delegate. You should attach a new set of attributes to the action delegate, declared within the graph extension. Also, you need to invoke the Press() method on the base graph action. Having redeclared the member of PXAction, you prevent the action delegate execution from infinite loops.
Explore the original action declaration and copy the declaration to the graph extension.
In the action declaration, set to false the Visible parameter of the PXUIField attribute, as the following code snippet shows.
...
[PXUIField(…, Visible = false)]
...
Replace the action delegate with the following code template.
public virtual IEnumerable myAction(PXAdapter adapter)
{
return Base.MyAction.Press(adapter);
}
In the code template, replace myAction and MyAction with the appropriate names.
In the template, redefine the action delegate arguments and return type according to the signature of the base action delegate.
If you have a customization that replaces an original action
declaration statically, after upgrading Acumatica ERP to a new
version, a new functionality of the same action may became
unavailable.
Also, if a callback command for the button is declared in the PXDataSource control, you can hide the button by customizing the ASPX code. To do this, in the Layout Editor, expand the PXDataSource control, select the appropriate PXDSCallbackCommand element, and set to False the Visible property of the element.
CREATE QUOTE button on the Requisition screen is implemented like a normal action in the RQRequisitionEntry BLC:
public class RQRequisitionEntry : PXGraph<RQRequisitionEntry>
{
...
public PXAction<RQRequisition> createQTOrder;
[PXButton(ImageKey = PX.Web.UI.Sprite.Main.DataEntry)]
[PXUIField(DisplayName = Messages.CreateQuotation)]
public virtual IEnumerable CreateQTOrder(PXAdapter adapter)
{
...
}
...
}
However, CREATE QUOTE button is added into the Actions drop down via Automation Steps:
With that said, the best way to customize the CREATE QUOTE button is by re-declaring the action within the RQRequisitionEntry BLC extension following sample below. I would be happy to come up with a more specific sample, if you provide additional details regarding your request.
public class RQRequisitionEntryExt : PXGraphExtension<RQRequisitionEntry>
{
public PXAction<RQRequisition> createQTOrder;
[PXButton(ImageKey = PX.Web.UI.Sprite.Main.DataEntry)]
[PXUIField(DisplayName = RQ.Messages.CreateQuotation)]
public virtual IEnumerable CreateQTOrder(PXAdapter adapter)
{
return Base.createQTOrder.Press(adapter);
}
}
I'm using the BTProgressHUD Xamarin component in an app that is built using MvvmCross. I'm currently working on the iOS version of the app. My ViewModels make several web service calls and expose an 'IsBusy' property, which the associated views are binding to, in order to show or hide the progress spinner. This is pretty much the way things are set up in the N=34 MvvmCross sample (https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/tree/master/N-34-Progress) as well.
The problem is that in some cases a ViewModel must automatically call a service as soon as it is created. I tried to make the call in the Start() function of the ViewModel, but I noticed that the BTProgressHUD spinner does not show up on top of the view. I suspect that the problem is that BTProgressHUD must be displayed only after a view has been made visible, and probably this is not the case when ViewModel.Start() runs.
Has anyone encountered this before? Is there a simple way to run code in the ViewModel after the view has been made visible?
Thanks.
Is there a simple way to run code in the ViewModel after the view has been made visible?
The N=42 video - http://slodge.blogspot.co.uk/2013/11/n42-is-my-viewmodel-visible-can-i-kill.html - introduces an IVisible interface that you can add to your ViewModel - it's your job to call this from your View - but this is easy to do on each platform. For example,, on iOS it is done using ViewDidAppear/ViewDidDisappear in https://github.com/MvvmCross/NPlus1DaysOfMvvmCross/blob/master/N-42-Lifecycles/Lifecycle.Touch/Views/FirstView.cs
protected IVisible VisibleViewModel
{
get { return base.ViewModel as IVisible; }
}
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
VisibleViewModel.IsVisible(true);
}
public override void ViewDidDisappear(bool animated)
{
base.ViewDidDisappear(animated);
VisibleViewModel.IsVisible(false);
}
We're using MVVMCross within our application and I've come up against something that I'm not sure I've solved in the best way possible.
One of our ViewModels contains 3 other view models - a dashboard and 2 lists. In iOS this is presented using a MvxTabBarViewController which works great. Android and WP present this view in a similar manner. An example of the object model is below:
public class ProjectViewModel : MvxViewModel
{
public DashboardViewModel Dashboard {get;set;}
public FirstListViewModel FirstList {get;set;}
public SecondListViewModel SecondList {get;set;}
}
We're now in the situation where if a certain action happens within the DashboardViewModel we would like to instruct the navigation to change the tab in iOS and the same thing to happen on the other platforms.
The only way I've been able to get the tab to change on iOS is to use this.SelectedIndex = 1; from within the iOS ProjectView.
At the moment also the only way I've managed to trigger this change is to fire an event from the DashboardViewModel and then the ProjectViewModel subscribes to this and fires another event which is subscribed to by the ProjectView to instruct it to change the tab in whatever device specific way it needs to. I can't help but think there is a better way to do this.
I've tried taking a look at a custom ViewPresenter for iOS and calling ShowViewModel FirstListViewModel from within the DashboardViewModel but the presenter doesn't appear to be getting used so we just transition normally. My idea was I could get in the middle, cancel the navigation request and then flip the active tab on the ProjectView.
Any suggestions would be appreciated on how we could do this in a better cross platform way using MVVMCross to handle the change if at all possible.
You should be able to do this in any of several ways:
using a custom presenter with overridden Show as you suggest
using a custom presenter with overridden ChangePresentation - and using a custom hint
using a custom binding or a binding to a property within the ProjectView to drive the transition
using a custom IMvxInteraction property
using a custom event from VM to View
using a messenger to send a message from the ViewModels to the Views.
Ultimately lots of these could work and which of these I might choose would depend on which one worked and which one the team are happy with - shipping the working app is always the ultimate goal.
Given where I am with MvvmCross experience, I'd probably opt today for trying the approach of trying a custom IMvxInteraction property. But this might not be for everyone... it certainly might be overkill for this sample...
However, to do this, I would try:
add a public enum Display { Dash, First, Second } to the Core project
add a ProjectViewModel property:
private MvxInteraction<Display> _display = new MvxInteraction< Display >();
public IMvxInteraction<Display> DisplayChange { get { return _display; } }
whenever this ViewModel wants to fire the change it can fire it using e.g. _display.Raise(Display.First)
the ProjectView could then bind Display to its own property which might be implemented like:
private IDisposable _subscription;
private IMvxInteraction<Display> _displayInteraction;
public IMvxInteraction<Display> ChangeDisplay
{
get { return _displayInteraction; }
set
{
if (_subscription != null)
{
_subscription.Dispose();
_subscription = null;
}
_displayInteraction = value;
if (_displayInteraction != null)
{
_subscription = _displayInteraction.WeakSubscribe(DoDisplayChange);
}
}
}
private void DoDisplayChange(Display which)
{
// change the tab display here
}
the binding would be added in ViewDidLoad like:
set.Bind(this).For(v => v.ChangeDisplay).To(vm => vm.DisplayChange);
In my app, one scene having the popup dialog which consists of some fields and buttons. If you click on the button then I want to dismiss the popup dialog as well as update the some fields in the scene. Indirectly I want to refresh scene. is it possible?
I used the following code.Here what I did is, I get the controller of that scene and then update the field using id. but it doesn't work.
URL location = AdmincontrolController.class.getResource("admincontrol.fxml");
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(location);
fxmlLoader.setBuilderFactory(new JavaFXBuilderFactory());
try {
Parent root = (Parent) fxmlLoader.load(location.openStream());
AdmincontrolController controller = fxmlLoader.getController();
System.out.println("AdmincontrolController: "+controller);
controller.setEmail(item.getEmail());
} catch (IOException ex) {
Logger.getLogger(Add_loginController.class.getName()).log(Level.SEVERE, null, ex);
}
Scenario:
scene
Popup - If we clicks on the add then we need to dismiss that dialog and change the email text on the previous scene.
As Alexander mentioned above, updating the underlying text property of the object you are using to display the email should Just Work. You need to make sure that you are working with the property (see Oracle Java FX Property Tutorial for more info). As a concrete example:
FXML
<Text fx:id="email" />
<TextField fx:id="emailInput" />
<Button onAction="#doSetEmail" text="Set Email"/>
In your controller, use the #FXML annotation to inject concrete instances of objects and set the handler to adjust the text:
Controller
#FXML
Text email;
#FXML
TextField emailInput;
#FXML
public void doSetEmail(ActionEvent ae) {
email.setText(emailInput.getText());
}
Alternatively, you could just bind the email text property to the email label property so that changes would automatically get propagated:
email.textProperty().bind(emailInput.textProperty());
You could do this in your controller initialize() method.
Now, the caveat to all this working depends on how you are handling the event and what you are doing in this. You still haven't posted the code for that as requested by the first answer, so you may be having issues there. Namely, if you are starting threads and then trying to update UI elements on the JavaFX thread from a worker thread, then you can get into trouble (potentially) with things not updating. This depends substantially on the structure of your objects, and you have not given enough information to comment in any meaningful way on that.
chooks
Everytime you have the Feeling that you manually want to update a Scene you should probably use a backgroundWorker Thread to do the work.
This way your UI Thread can use the time to update Labels etc.
JavaFX is built so that you don't need to directly call the scene update routine. All you need - update properties of scene components, and they will be updated on the nearest pulse.
So, all you need is to update properties. Or, is there any real trouble?
refreshing scene its not possible without closing...but if you can do class level declaration for control..i.e make them static its may work...
try this..
make a function in main file.
MainPanel.java
public static void SetMail(String email)
{
txtmail.setText(email);
}
LoginPanel.java
btnclear.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent t) {
MainPanel.SetMail(txtEmail.getText());
}
});