Progress KB - How to embed AppBuilder generated window in a .NET form ?




Feedback
Did this article resolve your question/issue?

   

Article

How to embed AppBuilder generated window in a .NET form ?

« Go Back

Information

 
TitleHow to embed AppBuilder generated window in a .NET form ?
URL NameP190039
Article Number000137364
EnvironmentProduct: OpenEdge
Version: 10.2x, 11.x
OS: Windows
Other: .NET UI
Question/Problem Description
How to embed AppBuilder generated window in a .NET form ?
How to avoid the error "The window may not be embedded because it has already been realized. (14837)"
Steps to Reproduce
Clarifying Information
Error Message
Defect/Enhancement Number
Cause
Resolution

 

When embedding an AppBuilder generated window in a .NET form, for a variety of reasons the window may be realized prematurely, causing the error:

The window may not be embedded because it has already been realized. (14837)

As a blanket approach to avoid this, it's possible to implement support code that allows the window to be embedded before any further code is executed. 
Since the goal is to embed the window as soon as possible after the AppBuilder generated CREATE WINDOW statement, the .w file needs to be modified. 
The following steps outline how to keep these modifications as transparent as possible:

1. Create a helper class that will handle the actual embedding:

/*------------------------------------------------------------------------
   File        : EmbedHelper.cls
   Purpose     : Runs .W for a window, and if window has helper code injected, makes sure window is 
                 embedded into WindowContainer or MDIChildForm.
   Syntax      : EmbedHelper:EmbedWindow (<filename.w>,<WindowContainer>|<MDIChildForm>)
 ----------------------------------------------------------------------*/

USING Progress.Lang.*.
USING Progress.Windows.*.

CLASS EmbedHelper:

    DEFINE PUBLIC STATIC PROPERTY ActiveWindowContainer AS Object NO-UNDO 
        GET.
        PRIVATE SET.

    /* since the EmbeddedWindow property isn't implemented in an interface or shared inherited type, 
      need to handle Progress.Windows.WindowContainer and Progress.Windows.MDIChildForm separately */      
    METHOD PUBLIC STATIC HANDLE EmbedWindow ( INPUT ProcedureName AS CHARACTER, INPUT TargetWindowContainer AS WindowContainer  ):  
        RETURN EmbedWindow(ProcedureName, CAST(TargetWindowContainer,Object) ).
    END METHOD.

    METHOD PUBLIC STATIC HANDLE EmbedWindow ( INPUT ProcedureName AS CHARACTER, INPUT TargetWindowContainer AS MDIChildForm  ):     
        RETURN EmbedWindow(ProcedureName, CAST(TargetWindowContainer,Object) ).
    END METHOD.

    METHOD PRIVATE STATIC HANDLE EmbedWindow ( INPUT ProcedureName AS CHARACTER, INPUT TargetWindowContainer AS Object  ):     
        DEFINE VARIABLE hProc AS HANDLE NO-UNDO.
        ActiveWindowContainer = TargetWindowContainer.
        RUN  value(procedurename) PERSISTENT SET hProc.
        ActiveWindowContainer = ?.
        
        RETURN hProc.

    END METHOD.

    METHOD PUBLIC STATIC HANDLE EmbedStep2 (INPUT WindowHandle AS HANDLE):
    
        DEFINE VARIABLE MDIChild     AS MDIChildForm    NO-UNDO.
        DEFINE VARIABLE WinContainer AS WindowContainer NO-UNDO.
    
        IF NOT VALID-OBJECT(ActiveWindowContainer) THEN 
            UNDO, THROW NEW AppError("EmbedStep2 should not be called directly. Use EmbedWindow instead").

        CASE ActiveWindowContainer:GetClass():TypeName:
            WHEN "Progress.Windows.MDIChildForm" THEN 
                DO:
                    MDIChild = CAST(ActiveWindowContainer, MDIChildForm).
                    MDIChild:EmbeddedWindow = WindowHandle.
                END.
     
            WHEN "Progress.Windows.WindowContainer" THEN 
                DO:
                    WinContainer = CAST(ActiveWindowContainer, WindowContainer).
                    WinContainer:EmbeddedWindow = WindowHandle.
                END.
        END CASE.    
       
    END METHOD.

END CLASS.


2. Create a helper include file, which invokes the  EmbedStep2 in the helper class:

/* EmbedHelperInject.i */

/* check if release is 10.2A or higher, so code compilable on earlier releases.
   note that this will break in OpenEdge 20.X due to string comparison */  
&IF NOT PROVERSION GE "2" AND PROVERSION GE "10.2A" &THEN
IF VALID-OBJECT(EmbedHelper:ActiveWindowContainer) THEN EmbedHelper:EmbedStep2(INPUT {&window-name}).
&ENDIF   



3. Using AppBuilder, add the helper include as the first method library in any .w that needs to be embedded
Procedure Settings -> Method Libraries -> Add.
Make sure the helper include is the first in the list.

In addition, if the window uses an icon, remove that in the AppBuilder property sheet, and add the appropriate code to load it at the start of the Main Block section:

&IF '{&WINDOW-SYSTEM}' NE 'TTY' &THEN
IF NOT C-Win:LOAD-ICON("<file name>":U) THEN
    MESSAGE "Unable to load icon: <file name>"
            VIEW-AS ALERT-BOX WARNING BUTTONS OK.
&ENDIF


Following these steps, the embedding code will literally be the first executable statement after the AppBuilder generated CREATE WINDOW. 
So here we accomplish our goal of embedding the Window widget at the earliest opportunity, and using this approach means the modification does not get wiped out if the window is saved using the AppBuilder again.

4. In the .NET form where the window should be embedded, use the helper class to run the window.w
This should be done in place of a RUN window.w PERSISTENT SET h statement.

EmbedHelper:EmbedWindow("window.w",myWindowContainer).

Using the helper class ensures that
 a) No attempt is made to embed an ABL window into a control other than a Progress.Windows.WindowContainer or Progress.Windows.MDIChildForm.
 b) The window being run is aware it's being embedded and completes the steps. This is what keeps the possibility to run the window outside of a .NET form.

Note that it remains the .NET form's responsibility to run additional initialization logic etc. (for example RUN InitializeObject IN h for a SmartWindow)

Workaround
Notes
References to Other Documentation:
 
OpenEdge Development: GUI for .NET Programming
OpenEdge Development: ADM and SmartObjects
OpenEdge Development: ADM Reference
 
Progress Articles:
Last Modified Date9/13/2015 10:05 AM
Attachment 
Files
Disclaimer The origins of the information on this site may be internal or external to Progress Software Corporation (“Progress”). Progress Software Corporation makes all reasonable efforts to verify this information. However, the information provided is for your information only. Progress Software Corporation makes no explicit or implied claims to the validity of this information.

Any sample code provided on this site is not supported under any Progress support program or service. The sample code is provided on an "AS IS" basis. Progress makes no warranties, express or implied, and disclaims all implied warranties including, without limitation, the implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or performance of the sample code is borne by the user. In no event shall Progress, its employees, or anyone else involved in the creation, production, or delivery of the code be liable for any damages whatsoever (including, without limitation, damages for loss of business profits, business interruption, loss of business information, or other pecuniary loss) arising out of the use of or inability to use the sample code, even if Progress has been advised of the possibility of such damages.