Acumatica Customization - How to remove anonymous delegate from PXGraph.RowInsertingEvents Collection? - c#

I‘m working on customization that involves adding extra Sales Person transactions when Cancelling/Correcting an Invoice. As part of the development effort, I have identified that the common method that’s called by both the processes – Cancel Invoice and Correct Invoice, is ReverseDocumentAndApplyToReversalIfNeeded in the Graph PX.Objects.AR.ARInvoiceEntry.
I have the custom code to add new salespersons to the ARInvoiceEntry.salesPerTrans view but when I do after ReverseDocumentAndApplyToReversalIfNeeded runs, I see that my code doesn’t insert the new records to the view and doesn’t give any error. After much troubleshooting, I’ve found out that there’s a line of code in the method ReverseInvoiceProc of ARInvoiceEntry.cs that stops from inserting a new row. Here’s that line of code:
this.RowInserting.AddHandler<ARSalesPerTran>((sender, e) => { e.Cancel = true; });
It’s an anonymous delegate that’s added.
I would like to know how can I get hold of this anonymous handler in my custom code so that I can:
Remove that anonymous handler
Do my custom logic of adding new rows
Add the anonymous delegate back to the RowInsertingEvents list
I tried to look in the Acumatica code repository but couldn’t find anything that would help me remove anonymous delegate. What I can find was the removal of named handlers, like the below example:
APPaymentEntry pe = CreateInstance<APPaymentEntry>();
pe.RowSelecting.RemoveHandler<APPayment>(pe.APPayment_RowSelecting);
So please let me know how can I dynamically remove that anonymous handler from within my custom code. I have reference to the ARInvoiceEntry graph through the Base property of my extension graph. If you can redirect me to a specific page in the Acumatica Code repository, that would work as well.

I do not think you could remove this anonymous method from there in a easy way.
However, one approach you could implement is to override the "ReverseDocumentAndApplyToReversalIfNeeded" method and call base method there.
After this you could create a new instance of the ARinvoiceEntry graph (in that same override after calling base method), select the primary record(header) and then try to make your second insert ( this way to avoid the ReverseInvoiceProc.)

Related

How to best store commands and their response code for a .NET console app?

Description
My app takes user input (ReadLine()) and calls its corresponding function as a result.
At the moment, it's just a switch that checks for certain commands, with their response code inside cases, but I though I ought to separate them for cleaner code.
What's the design pattern of choice here?
Attempted Solution
I could make an abstract Command class with a commandName field and a mandatory Respond() function. Then, I'd hold a List of Commands, iterate over each to check if its commandName matches what the user input, and call its Respond() function (and break the loop) if so.
Problem
That still necessitates manually creating instances of each Command and adding them to the List that holds them.
If possible, I'd like for each Command to be automatically added. I wish to instruct the program to loop over every class in a Commands/ directory and instantiate and add it on its own, or something like that.
Can I do that? If not, what's the best alternative?
You have two solutions for what you are trying to achieve:
Reflection. You can use reflection to find all the classes that extend the abstraction of command.
var type = typeof(IMyInterface);
var types = AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => type.IsAssignableFrom(p));
Then
// use activator to create an instance and add it to list
list.Add(Activator.CreateInstance(types[0])) // etc
Use dependency injection to create the list of types, by configuring a json or other configuration file.
This varies greatly, depending on the di framework of your choice.

Link Xamarin properties from different ViewModels

Is it possible to just "link" two properties of different ViewModels in a way such that when one property changes, the other one changes too. So in essence, I want two properties in different ViewModels behave as if they were one.
It would be nice if I could just do something like the following in my ViewModels:
WhenPropertyChanges(() => SettingX).CopyValueTo(() => ModelView2.SettingX);
Example: On my settings page, when I change a setting, I want the new value to be available in the ViewModel of another page.
I know I can achieve that with the third Layer (Model), but it feels a bit clunky and the way I solved it for now doesn't feel right (Firing events).
I've implemented following MVVM-Pattern from this page: http://www.wintellect.com/devcenter/krome/linking-property-change-notifications-in-xamarin-forms-or-wpfsilverlight. As far as I understood, the author says his code makes it possible, but unfortunately he doesn't show how.
I also found this article (http://blog.alectucker.com/post/2014/07/26/using-messageingcenter-in-xamarin-forms-for-viewmodel-to-viewmodel-navigation.aspx), but I don't necessarily want to navigate to the other View. Still, maybe I can use this MessagingCenter somehow to achieve my goal?
This is addressed in the final paragraph of my article that you reference. I use a simple extension method to do it. An example of this can be seen in the source code example from the article, in this file: https://github.com/Wintellect/XamarinSamples/blob/master/PropertyDependencyDemo%2FPropertyDependencyDemo%2FMvvm%2FObservableExtensions.cs
For your specific example, it would look something like this:
// using PropertyDependencyDemo.Mvvm;
// ... use the namespace above that contains the ObservableExtensions class
ModelView1
.WhenPropertyChanges((a) => a.SettingX)
.AlsoInvokeAction(() => ModelView2.SettingX = ModelView1.SettingX);
All this does is hook into the PropertyChanged event of the source viewmodel for you in a name-safe way.
One word of caution though: you need to be careful to not create a situation where you inadvertently prevent an object from being garbage collected. The reason this can happen is that in this example, ViewModel1 will now have a PropertyChanged handler that references a PropertyDependency object that in turn references both ModelView1 and ModelView2 due to the captured references in the Action lambda expression.
IF you know for sure that this won't be a problem (perhaps both go out of scope together), then there is nothing to worry about. But if you find yourself facing a situation where you need to prevent ModelView1 from keeping ModelView2 pinned, then you can do so using a WeakReference. Again, this is unlikely to be a concern, but if you find it leaking memory then you can change the above to this:
// assuming "TModelView" is the class name of the viewmodels
var wr = new WeakReference<TModelView>(ModelView2);
ModelView1
.WhenPropertyChanges((a) => a.SettingX)
.AlsoInvokeAction(() => {
TModelView mv;
if (wr.TryGetTarget(out mv))
mv.SettingX = ModelView1.SettingX;
});
I think if the navigation is lineare ( you only need the information of page 1 in page 2 ) you can use the MessagingCenter to do what you want.
If the user is able to change the data in the page 2 ( and be updated in the page 1 ) the messagingCenter is a little to tricky to use. I think you can use the first link you provide. Just use an abstract class with all shared data in your ViewModels.
If you want more help put an more completed code example.

Serialization of only changed members

I am new to MongoDB and want to serialize my object efficiently. That means when updating an object i want only to write the fields that changed. If my object has sub objects in a list, i only want to add or remove the changed sub objects. That is because if i have a post with 1000 comments i want to avoid to serialize the whole object each time a new post comes around.
all i found is the convention ignoreifempty, ignoreisdefault and the shouldserializexyz pattern.
is it possible to write a convention like ignoreifnotchanged (i track the dirty fields in my objects) or is there a more general shouldserializexyz because i don't want to write the method for every property.
What you want to look into is the Update method with an update argument that specifies which fields you want to update.
You can use the Update builder to build the update argument value. Look into:
Update.Set(name, value)
Update.Push(name, value)
(there are many more also).
You can chain Update methods together to update more than one field at a time.
There is currently no built in change tracking, so you would have to keep track of which fields have changed yourself, and build the update argument based on your knowledge of what changed.
There is also a pending JIRA feature request that is related to this. See:
https://jira.mongodb.org/browse/CSHARP-237
Please comment or vote on the JIRA if you want.

Monotouch: send data back down the stack to another ViewController

I have a question concerning Monotouch.
The situation: I have 2 ViewControllers. The first (let's call it VC-A) looks similar to the contacts edit screen, meaning it has a TableView with multiple Sections each containing Buttons and TextFields. Now when the user clicks one of these Buttons, he will get to the second ViewController (VC-B), which displays a TableView containing data from the database. When the user clicks on any of these rows, VC-B will be closed and i want to display the selected database entry (string) as the title of the Button (in VC-A) which opened VC-B in the first place.
When I did an objective-C project last year, I managed to send data back down the stack by using delegates, but I haven't found a way yet how this works in Monotouch.
I have read several questions here on SO about using the AppDelegate or using singletons, but I'm not sure that this is the right way of returning data from a subview.
You can kind of copy the delegate pattern. Add a C# delegate to your VC-B that takes one parameter, some data structure.
In VC-B's "ViewWillDisappear", call the delegate it it is not null and pass the data on to it.
This way, your calling VC can get acces to the data but you don't need tight coupling between the two controllers. All it has to do, is register a delegate-method in VC-B.
As MonoTouch is .NET4 you can use Func<MyDataStructure> or Action<MyDataStructure> and don't need to use full qualified delegate types.
I have a static singleton class that I use to store "state" type data about my app - current settings and selections that are needed in many different places in the app. That's one way to approach this.
You could also pass VC-B a reference to VC-A when you create VC-B, so that it can explicitly access it's parent view and pass back values that way.
I actually prefer to use TinyMessenger for cross container calls I find this to be very very useful when you don't want to keep references to your heavy viewcontrollers around which could potentially result in memory leaks!
var messageHub = new TinyMessengerHub();
// Publishing a message is as simple as calling the "Publish" method.
messageHub.Publish(new MyMessage());
// We can also publish asyncronously if necessary
messageHub.PublishAsync(new MyMessage());
// And we can get a callback when publishing is completed
messageHub.PublishAsync(new MyMessage(), MyCallback);
// MyCallback is executed on completion
https://github.com/grumpydev/TinyMessenger

C# asp.net custom MembershipUser.createUser() method, call it from createuserwizard control

I have created custom MembershipUser, MembershipProvider and RolePrivoder classes. These all work and I am very happy with it, apart from one thing. I have an extra field in the "Users" table. I have an overridden method for CreateUser() that takes in the extra variable and puts it into the DB.
My issues is that I want to be able to have this called from the Create User Wizard control. I have customized the control to have a drop down to populate my extra field. I have used the following code to store that piece of info but I am at a loss of how I either use the profile or call my custom CreateUser Method:
// Create an empty Profile for the newly created user
ProfileCommon p = (ProfileCommon)ProfileCommon.Create(CreateUserWizard1.UserName, true);
// Populate some Profile properties off of the create user wizard
p.CurrentLevel = Int32.Parse(((DropDownList)CreateUserWizard1.CreateUserStep.ContentTemplateContainer.FindControl("clevel")).SelectedValue);
// Save profile - must be done since we explicitly created it
p.Save();
Thank you for any and all help
Jon Hawkins
I think your solution is the "easiest" you're going to get. You could create your own wizard and call the correct method, but that's a lot more work.
The only thing I could recommend is using the OnCreatedUser event instead.
reference: 4guysfromrolla
This is not the answer but I found a work around, would still like to know if someone could answer the question directly...
public void UpdateCurrentLvl_OnDeactivate(object sender, EventArgs e)
{
int level = Int32.Parse(((DropDownList)CreateUserWizard1.CreateUserStep.ContentTemplateContainer.FindControl("clevel")).SelectedValue);
MyMembershipUser myUser = (MyMembershipUser)Membership.GetUser(CreateUserWizard1.UserName);
myUser.CurrentLVL = level;
Membership.UpdateUser(myUser);
}
In my first CreateUserWizardStep if put the method above to fire on deactivate. As at this point it has inserted the user into the DB I can get the User out, cast to my MembershipUser class, set the variable and all the update method.
As I say this is a work around from the way I would liked to have solved it but it works.
Thanks
This is also incredibly hacky, but in the past when I've had to do similar things, I've just crammed the extra value into an unused parameter, like the password reset question or answer. Though, I'm not entirely sure how you'd manage this using the wizard.
It's ugly, but as long as it is explicitly documented (to be safe, I'd comment on the method itself as well as anywhere you reference it) it will work fine.
It's also a lot less work than creating your own wizard.

Categories