New Action Definitions on a custom screen - acumatica

I am trying to implement the new action definitions on a custom screen in 2020R1 in preparation for 2021R2. I cant seem to get these actions to group into folders, and the last action will not hide. What am I missing?
This is in the graph definition:
public override void Configure(PXScreenConfiguration graph)
{
var context = graph.GetScreenConfigurationContext<NGBiopsyEntry, NGBiopsy>();
context.AddScreenConfigurationFor(screenConfig =>
screenConfig
.WithActions(actions =>
{
actions.Add(a=>a.ActionSubmitBiopsy);
actions.Add(a=>a.ActionRefreshWorkTickets,
config=>config
.InFolder(FolderType.ActionsFolder));
actions.Add(a=>a.ActionStartPGTMTesting,
config=>config
.InFolder(FolderType.ActionsFolder));
actions.Add(a=>a.ActionSetEmbryoIDGen,
config=>config
.InFolder(FolderType.ActionsFolder)
.IsHiddenAlways());
}));
}
But still I get this:
Even after restarting the application, rebuilding the dll, publishing the customization project. Is there another setting I Am missing?

The new workflow is pretty entertaining to sort out. There was a great presentation at Summit this year, so keep an eye out for when the post the video to get a lot of great additional detail. This should be a pretty easy fix, but it isn't universal so I'll share the 2 ways you might have to add your menu actions.
The first thing that got my attention is that your menu actions are not in the Actions folder as you specified. That's a pretty clear sign that the context isn't quite right. I break mine into 2 parts, and I think you set yours with a single method.
In both cases, you need to start by overriding Configure, specifying the graph and primary DAC. Then you define a Configure using your WorkflowContext specific (again) to your graph and primary DAC. After that, things start to become a little more complicated.
Is this for a new custom screen that has no screen configuration yet, or are you extending a workflow that already exists? In the first example, I am adding a couple of print actions to the POReceiptEntry graph which already has a workflow (and screen configuration) defined. Also, I'm adding my action from the POReceiptEntry_Extension class, so I need to specify that on the Add.
public override void Configure(PXScreenConfiguration config)
=> Configure(config.GetScreenConfigurationContext<POReceiptEntry, POReceipt>());
protected virtual void Configure(WorkflowContext<POReceiptEntry, POReceipt> context)
{
context.UpdateScreenConfigurationFor(screen =>
{
return screen
.WithActions(actions =>
{
actions.Add<POReceiptEntry_Extension>(
g => g.printItemLabel,
a => a.InFolder(FolderType.ActionsFolder)
);
actions.Add<POReceiptEntry_Extension>(
g => g.printSOLabel,
a => a.InFolder(FolderType.ActionsFolder)
);
});
});
}
When adding an action to a custom screen, the screen configuration is not created until you create it. In this example, you will see UpdateScreenConfigurationFor is changed to AddScreenConfigurationFor. Also, you will see that Add does not specify the extension this time because the actions are defined in my custom (base) graph.
public override void Configure(PXScreenConfiguration config)
=> Configure(config.GetScreenConfigurationContext<MyGraph, MyDAC>());
protected virtual void Configure(WorkflowContext<MyGraph, MyDAC> context)
{
context.AddScreenConfigurationFor(screen =>
{
return screen
.WithActions(actions =>
{
actions.Add(
g => g.myAction,
a => a.InFolder(FolderType.ActionsFolder)
);
});
});
}
Notes to other readers:
I'm using 2021R1, and for everyone else's benefit, I've talked with Kyle and learned he is using 2020R1. His specific implementation is a bit more complex, and he needed to add
.AddDefaultFlow(workflow => workflow...
to create his default workflow. This can be done in the screen definition as well from the screen editor in the customization project, although I cannot recall if our SysAdmin did that or if AddScreenConfiguration in my example handled it for me.

Related

Problem with binding to MvxView with Xamarin.iOS and MvvmCross

I have a problem with implementing following scenario using Xamarin.iOS and MvvmCross (6.2.3.0). I have a view and in it's viewmodel I have a property which is a list of objects. I need to dynamically generate a label and a textfield for each of this list entry on my view. So I decided to implement a custom view for this. Here is what I tried so far:
In my viewcontroller, in CreateView I simply add my custom UIView. I can see it's content on my view. In ViewDidLoad() I create bindings:
private void CreateBindings()
{
var set = this.CreateBindingSet<MyController, MyViewModel>();
set.Bind(myCustomControl).For(x => x.DataContext).To(vm => vm.MyListOfObjects);
set.Apply();
}
MyCustomControl code is as follows:
public class MyCustomControl : MvxView
{
public MyCustomControl() {
//DataContext is always null here!
//I'd like to get access to list of objects here, add controls for each entry and make sure they are binded to a viewmodel's list of objects somehow.
}
}
I noticed that the list of objects in my viewmodel is set later than a constructor call for MyCustomControl is being made, so it makes sense that DataContext in MyCustom control is null. I'm missing something obvious I believe. Can someone point me in a proper direction? I would be very grateful.
I tried this example, which is exactly what I'm trying to achieve, but no luck so far ;(
N=32 - ViewModels and MvxView on the iPad - N+1 days of MvvmCross
https://www.youtube.com/watch?v=cYu_9rcAJU4&list=PLR6WI6W1JdeYSXLbm58jwAKYT7RQR31-W&index=35&t=1649s
Take a look at 23:43 of the video you posted.
You should do the view binding inside a DelayBind method.
this.DelayBind(() => {
var set = this.CreateBindingSet<MyCustomControl, MyItemViewModel>();
set.Bind(badgeLabel).For(v => v.Text).To(x => x.BadgeText);
set.Bind(topSummary).For(v => v.Text).To(x => x.TopSummary);
set.Bind(bottomSummary).For(v => v.Text).To(x => x.BottomSummary);
set.Bind(this.Tap()).For(v => v.Command).To(x => x.Edit);
set.Apply();
});
MvvmCross will do the binding for you.
Also Mind that the proper types have to be passed to CreateBindingSet.
On a side node, MvvmCross N+1 videos are from 2013 and some things has changed since then.
You can find some good examples there but sometimes it just won't work anymore.
If you are new to MvvmCross, download the source code of Playground project for reference:
https://github.com/MvvmCross/MvvmCross/tree/develop/Projects/Playground
and join the #mvvmcross slack channel if you need more help
https://xamarinchat.herokuapp.com/
MvvmCross is really great... once you grasp the basic concepts.

Implement missing members - add async when return type is Task?

This question relates to ReSharper. If I have an interface that looks like this:
public interface IOrder {
Task SetDeleted(Guid id);
}
and my class inherits from that interface, I would expect ReSharper to generate the following code, when selecting the "Implement missing members":
public class OrderService {
public async Task SetDeleted(Guid id) {
throw new NotImplementedException();
}
}
However, it completely ignores the async part of the method, so I have to type that manually every single time. This was fixed in 2016.3 of ReSharper, as described here (at the bottom).
However, it does not work for the CTRL + . keybinding (or whatever it is), that looks like this:
Is it possible to somehow change, how this behavior works within ReSharper? I want all generated Task methods to be async automatically. There is no option within ReSharper's "Members Generation" that enables me to do this.
In case class has only one missing member ReSharper doesn't show dialog therefore you can't tweak generation options. But you can add one more member to your interface and invoke generation action, this time ReSharper would show the dialog where you can set option "Make task-returning methods 'async'". This generation option is persistent i.e. it's last value will be stored in ReSharper settings and used by default.

Pluralsight Advanced - Movie Content not displayed in Content table

I am walking through Pluralsight Advanced Orchard course.
I just created the Movie module and created a sample movie.
It was working fine but I did notice that the sample movie did not show up in Manage Content page.
I can only get to the list by going to Content Definition and select "List Items"
Then I can see the list of Movie item
This is what I got so far. I followed the steps and don't see what I have missed. I did notice that Orchard has changed slightly from 1.4 to 1.10 appearance wise. I wonder if this also has something to do with the version difference.
Any tips would be appreciated! Thank you
namespace Pluralsight.Movies {
public class Migrations : DataMigrationImpl {
public int Create() {
ContentDefinitionManager.AlterTypeDefinition("Movie", builder=>
builder.WithPart("CommonPart")
.WithPart("TitlePart")
.WithPart("AutoroutePart")
.WithPart("BodyPart")
.Creatable()
.Draftable());
return 1;
}
public int UpdateFrom1()
{
ContentDefinitionManager.AlterTypeDefinition("Movie", builder =>
builder.WithPart("BodyPart", partBuilder=>partBuilder.WithSetting("BodyTypePartSettings.Flavor", "text")));
return 2;
}
}
Try to add .Listable() into your type definition. Note that if you already ran those migrations, unless you reset the database, it won't execute again, so you'll have to put it into a UpdateFrom2() method.
Note that this setting can also be checked from the content definition screen after the fact.
Note: I think the PluralSight course was written at a time when this setting didn't exist, and everything was listable.

Synchronising GEF editor with EMF model with two EMF adapters

I'm having trouble synchronising my GEF editor with the EMF-based model. I think this is due to the fact that the model-internal EMF Adapter, or rather the methods it calls, aren't finished before the editor's Adapter's notifyChanged() is called and updates the model children. This leads to the editor view being out-of-sync with the model itself, or rather, the changes to the model not being represented in the view when they should be.
Consider this set up. A Command "CreateNodeCommand" adds a node to the underlying model:
#Override
public void execute() {
...
getNewNode().setGraph(getGraph());
...
}
The GraphEditPart has an internal class extending org.eclipse.emf.common.notify.Adapter. It's notifyChanged() method is indeed notified, as tested similar to below (incomplete code):
#Override
public void notifyChanged(Notification notification) {
switch (notification.getEventType()) {
case Notification.ADD:
System.err.println("ADD occurred!");
refreshChildren();
}
The problem is, that the (third-party) model itself also implements an Adapter, which in turn runs a number of methods on the new model element, such as adding an ID, etc.
It seems to me that the fact that the new element's figure doesn't show up in the editor directly after it's been created - but only after the next editing step, the figure for which then doesn't appear - suggests that the model adapter is still busy setting up the new element while refreshChildren() is already being called by the editor adapter.
This seems to call for synchronisation, but I'm unsure whether this can be achieved with built-in Java functionality for multithreading, or calls for an EMF-based approach.
Please share your knowledge about synchronising in EMF.
Many thanks in advance!
EDIT
On request, here is the source code for the getModelChildren() method:
#Override
protected List<EObject> getModelChildren() {
List<EObject> allModelObjects = new ArrayList<EObject>();
allModelObjects.addAll(((MyGraph) getModel()).getTokens());
allModelObjects.addAll(((MyGraph) getModel()).getNodes());
return allModelObjects;
}
Debugging the (3rd party) model, I found out that the Graph's enotify() fired the notification before the actual adding took place, hence my Adapterreceived the notification too early, i.e., before the node had been added.
The notification is now called after the add and everything works fine.
Thanks for all of your help!
Try extending EContentAdapter instead of AdapterImpl, and not forget to call
super.notifyChanged(Notification notification);
in it. It's an adapter, which will add itself to new elements of the model, and notify you then they are changed.

Orchard Custom User Part is not stored in Database

I can't seem to store additional data in a separate contentpart attached to User. I have done the following:
Created a module
In the module I created a Model for ProfilePart and ProfilePartRecord
In the migration I created a table for ProfilePartRecord (from type ContentPartRecord)
In the migration I altered the typedefinition for User, by setting WithPart ProfilePart
I created a driver class, that has 2 edit methods, one for get and one for post (code snippets are below
I also created a handler that adds a storage filter for profilePartRepository of type ProfilePartRecord
Module Structure
Drivers/ProfilePartDriver.cs
Handlers/ProfileHandler.cs
Models/ProfilePart.cs
Models/ProfilePartRecord.cs
Views/EditorTemplates/Parts/profile.cshtml
Migrations.cs
Placement.info
Since I think the issue is in the Driver. This is my code:
Is it going wrong because the part is attached to User? Or am I missing something else.
public class ProfilePartDriver:ContentPartDriver
{
protected override string Prefix
{
get { return "Profile"; }
}
//GET
protected override DriverResult Editor(ProfilePart part, dynamic shapeHelper)
{
return ContentShape("Parts_Profile_Edit", () =>
shapeHelper.EditorTemplate(TemplateName: "Parts/Profile", Model: part, Prefix: Prefix));
}
//POST
protected override DriverResult Editor(ProfilePart part, IUpdateModel updater, dynamic shapeHelper)
{
updater.TryUpdateModel(part, Prefix, null, null);
return Editor(part, shapeHelper);
}
}
I have used Skywalker's blog. There is one chapter about registering customers by using the User and adding your own content parts to it. Worked nice for me.
First of all - is your ProfilePart editor shown at all when you go to Dashboard and edit a given user? I noticed you're using Parts_Profile_Edit as a shape key, but actually use EditorTemplates/Parts/Profile.cshtml as a template. It's perfectly correct, but note that Placement.info file uses shape keys, so you have to use Parts_Profile_Edit as a shape name in there. Otherwise it won't get displayed.
Second - have you tried debugging to see if the second driver Editor method (the one for handling POST) is being called at all?
Like Bertrand suggested, I'd look into one of the existing modules that work (afaik there is one for user profile in the Gallery) and see the difference. It might be something small, eg. a typo.

Resources