0
votes

I'm attempting to create a graph extension to modify the behavior of one of the mobile scan screens, and I found in developer release notes for 2020 R1 the ability to use the [PXProtectedAccess] attribute to utilize protected members of a Graph from the extension, even though it does not directly inherit from it.

However, in order to utilize this, the Graph Extension class needs to be abstract and Acumatica no longer seems to recognize it when I do so. I'm sure that I am missing a crucial piece here but I can't figure out what it is based on documentation. EDIT: I was missing the [PXProtectedAccess] attribute on the class itself.

Now I am seeing something else when I try to actually call the abstract method. It throws Unable to cast object of type 'Wrapper.PX.Objects.IN.Cst_INScanIssueHost' to type 'INScanIssueHostDynamicInterface'. when I attempt to call any one of these protected members. I'm not sure what INScanIssueHostDynamicInterface refers to or how to resolve the type conflicts here.

Here is an excerpt of the code I'm using:

    [PXProtectedAccess]
    public abstract class INScanIssue_Extension : PXGraphExtension<INScanIssue, INScanIssueHost>
    {
        [PXProtectedAccess]
        protected abstract void ReportError(string errorMsg, params object[] args);

        public delegate void ProcessConfirmDelegate();
        [PXOverride]
        public virtual void ProcessConfirm(ProcessConfirmDelegate baseMethod)
        {
            ReportError("TEST");
        }
    }
2

2 Answers

2
votes

I think you are on the right path. Your graphExtension should be abstract. Also please note that on your extension you use protected member of the graph extension by specifying the parameter of the attribute, as shown below:

public class MyGraph : PXGraph<MyGraph>
{
   protected void Bar() { }
}

public class MyExt : PXGraphExtension<MyGraph>
{
   protected void Foo() { }
}

[PXProtectedAccess]
public abstract class MySecondLevelExt : PXGraphExtension<MyExt, MyGraph>
{ 
    [PXProtectedAccess]
    protected abstract void Bar();

    [PXProtectedAccess(typeof(MyExt))]
    protected abstract void Foo();
 }

So in your case, I think you can try to add that parameter to the ProctectedAccess attribute for those members that from INScanIssue(or overriden there ):

namespace PX.Objects.IN
{
   [PXProtectedAccess]
   public abstract class INScanIssue_Extension : PXGraphExtension<INScanIssue, 
       INScanIssueHost>
{
    public static bool IsActive()
    {
        return true;
    }

    # region Protected Access

    *[PXProtectedAccess(typeof(INScanIssue))]*
    protected abstract void ClearHeaderInfo(bool redirect = false);

    [PXProtectedAccess]
    protected abstract void SetScanState(string state, string message = null, params object[] args);

    [PXProtectedAccess(typeof(INScanIssue))] 
    protected abstract bool PromptLocationForEveryLine { get; }
........................................
0
votes

Use the abstract extension only to access the protected members, then add a second level extension, that calls the exposed members from your first level extension. And I don't think you need to apply the attribute on the extension.

public abstract class INScanIssueProtectedAccessExt : PXGraphExtension<INScanIssue, INScanIssueHost>
{
    [PXProtectedAccess]
    public abstract void ReportError(string errorMsg, params object[] args);
}

public class INScanIssue_Extension : PXGraphExtension<INScanIssueProtectedAccessExt, INScanIssue, INScanIssueHost>
{      
    public delegate void ProcessConfirmDelegate();
    [PXOverride]
    public virtual void ProcessConfirm(ProcessConfirmDelegate baseMethod)
    {
        this.Base2.ReportError("TEST");
    }
}