Using Viewer Logic Classes

The Viewer Logic class supports developers to separate viewer event handling logic from the actual layout of viewers. This includes the ability to handle input control based events in a single place, no matter if due to layout constraints the controls are spread over more than a single viewer (GroupAssignLink) or certain fields are not used on viewers at all (e.g. due to customization etc.) and thus might cause errors.

To facilitate this developers can move the viewer event handling logic from the actual SmartViewerControl derived classes into ViewerLogicClasses.

The name of a ViewerLogicClass needs to be registered on the viewer instance in the form using the ViewerLogicClass property and the viewer will load and initialize this class during the Load event.


The ViewerLogicClasses needs to implement the Interface:

Consultingwerk.SmartComponents.Interfaces.ISmartViewerLogic


The suggested way to implement the Interface is to inherit from the abstract class:

Consultingwerk.SmartComponents.Base.SmartViewerLogic


When using the ViewerLogicClass to handle events of controls on a viewer you need to subscribe to events of the Controls and also unsubscribe those events when the Form containing the Viewer is closed to prevent memory leaks.

For event subscription and unsubscription the abstract SmartViewerLogicClass enforces the implementation of the two methods SubscribeEvents and UnsubscribeEvents:

/*------------------------------------------------------------------------------
    Purpose: Subscribes the events for an attached viewer instance
    Notes:   This method needs to be implemented by the Viewer Logic class and
             is supposed to subscribe to control events
  ------------------------------------------------------------------------------*/
METHOD OVERRIDE PUBLIC VOID SubscribeEvents ():
END METHOD .

/*------------------------------------------------------------------------------
    Purpose: Unsubscribes the events for an attached viewer instance
    Notes:   This method needs to be implemented by the Viewer Logic class and 
             is supposed to unsubscribe from control events
  ------------------------------------------------------------------------------*/
METHOD OVERRIDE PUBLIC VOID UnsubscribeEvents ():
END METHOD . 

The ViewerLogicClass base class provides three API’s to query the availability of Controls data bound to certain fields in the binding source on the linked viewers and to retrieve the references to those controls:

 

/*------------------------------------------------------------------------------
    Purpose: Returns the reference to the first Control that is bound to the named
             field of the binding source
    Notes:   Searchs all Controls in the owning viewer and also GroupAssignLinked viewers
    @param pcBindingPropertyName The name of the field in the ProBindingSource
    @return The bound Control of ? when no Control is bound
------------------------------------------------------------------------------*/
METHOD PUBLIC System.Windows.Forms.Control GetBoundControl (pcBindingPropertyName AS CHARACTER).


/*------------------------------------------------------------------------------
    Purpose: Returns the list of references of the Controls that are bound to the
             named field of the binding source
    Notes:   Returns all Controls in the owning viewer and also GroupAssignLinked viewers
    @param pcBindingPropertyName The name of the field in the ProBindingSource
    @return The List of bound Controls
  ------------------------------------------------------------------------------*/
METHOD PUBLIC "System.Collections.Generic.List<System.Windows.Forms.Control>" GetBoundControls (pcBindingPropertyName AS CHARACTER).


/*------------------------------------------------------------------------------
    Purpose: Returns logical value indicating if the Viewer contains a Control
             that is bound to the named field
    Notes:   Includes Group Assigned viewers
    @param pcBindingPropertyName The name of the field in the ProBindingSource
    @return Logical value indicating if a bound control exists
  ------------------------------------------------------------------------------*/
METHOD PUBLIC LOGICAL HasBoundControl (pcBindingPropertyName AS CHARACTER). 

As these methods are implemented in the base class of the actual ViewerLogicClasses, there are accessible using the THIS-OBJECT reference.

The pcBindingPropertyName parameter to all those API’s should contain the name of the column as it appears in the BindingSource. Typically this is either just the field name or a combination of the table name and the field name delimited with the colon character.

 

The method Consultingwerk.Util.BindingSourceHelper:BindingColumnName may be used to determine the column name for a given buffer field.

 More info: http://help.consultingwerkcloud.com/smartcomponent_library/release/Consultingwerk.Util.BindingSourceHelper.html

Subscribing and unsubscribing to events

Due to the fact that there should be no tight binding between the ViewerLogicClass and the actual viewers, events should be bound to control references based on the binding source columns names. A typical flow would be like this:

IF THIS-OBJECT:HasBoundControl ("CustNum") THEN

    THIS-OBJECT:GetBoundControl ("CustNum"):Validating:Subscribe (ValidatingEventHandler).

 

When you are expecting a list of Controls for that column, you need to use the GetBoundControls method which returns a list.

    {Consultingwerk/foreach.i System.Windows.Forms.Control oControl in "THIS-OBJECT:GetBoundControls(""CustNum"")"}

    oControl:Validating:Subscribe (ValidatingEventHandler).

END.

 

When you need to subscribe to events that are not defined only on the specific Control type (e.g. CheckChanged of the combo-box Controls), the Control reference received from the GetBoundControl/GetBoundControls API’s need to be casted.

The validating event handler needs to be implemented in the viewer logic class with an appropriate signature.

Within the event handler method, the Control reference can be obtained by CAST’ing the sender input parameter to System.Windows.Forms.Control.

The included files Consultingwerk/subscribeviewerevent.i and Consultingwerk/unsubscribeviewerevent.i simplify the subscription and unsubscription of events.


Example: CustomerViewerLogic.cls

/**********************************************************************
 * Copyright (C) 2006-2013 by Consultingwerk Ltd. ("CW") -            *
 * www.consultingwerk.de and other contributors as listed             *
 * below.  All Rights Reserved.                                       *
 *                                                                    *
 *  Software is distributed on an "AS IS", WITHOUT WARRANTY OF ANY    *
 *   KIND, either express or implied.                                 *
 *                                                                    *
 *  Contributors:                                                     *
 *                                                                    *
 **********************************************************************/
/*------------------------------------------------------------------------
    File        : CustomerViewerLogic
    Purpose     : Logic class for customer viewer instances
    Syntax      : 
    Description : 
    Author(s)   : Mike Fechner / Consultingwerk Ltd.
    Created     : Sun Sep 08 21:51:30 CEST 2013
    Notes       : 
  ----------------------------------------------------------------------*/
ROUTINE-LEVEL ON ERROR UNDO, THROW.
USING Consultingwerk.SmartComponents.Enum.*                          FROM PROPATH .
USING Consultingwerk.SmartComponents.Base.*                          FROM PROPATH .
USING Consultingwerk.SmartComponentsDemo.CustomerExplorer.Customer.* FROM PROPATH .  
USING Progress.Lang.*                                                FROM PROPATH .
CLASS Consultingwerk.SmartComponentsDemo.CustomerExplorer.Customer.CustomerViewerLogic 
    INHERITS SmartViewerLogic: 
    /*------------------------------------------------------------------------------
        Purpose: Constructor for the CustomerViewerLogic class
        Notes:   
    ------------------------------------------------------------------------------*/
	CONSTRUCTOR PUBLIC CustomerViewerLogic ():
		SUPER ().
		
	END CONSTRUCTOR.
    /*------------------------------------------------------------------------------
        Purpose: Subscribes the events for an attached viewer instance
        Notes:   This method needs to be implemented by the Viewer Logic class and 
                 is supposed to subscribe to control events
    ------------------------------------------------------------------------------*/
	METHOD OVERRIDE PUBLIC VOID SubscribeEvents ():
        {Consultingwerk/subscribeviewerevent.i EmailAddress Validating ValidateEmailHandler}
	END METHOD .
    /*------------------------------------------------------------------------------
        Purpose: Unsubscribes the events for an attached viewer instance
        Notes:   This method needs to be implemented by the Viewer Logic class and 
                 is supposed to unsubscribe from control events
    ------------------------------------------------------------------------------*/
    METHOD OVERRIDE PUBLIC VOID UnsubscribeEvents ():
        {Consultingwerk/unsubscribeviewerevent.i EmailAddress Validating ValidateEmailHandler}
    END METHOD .
    /*------------------------------------------------------------------------------
        Purpose: Event handler for the Validating event of the Email field
        Notes:   
        @param sender The reference to the Control that raised the event
        @param e The CancelEventArgs with the data for this event 
    ------------------------------------------------------------------------------*/
	METHOD PROTECTED VOID ValidateEmailHandler (sender AS System.Object,
	                                            e AS System.ComponentModel.CancelEventArgs):
		
		DEFINE VARIABLE cEmail AS CHARACTER NO-UNDO.
		
		IF THIS-OBJECT:Owner:SmartTableIOState = TableIOStateEnum:FieldsEnabled THEN
		    RETURN . 
		   
		ASSIGN cEmail = CAST (sender, System.Windows.Forms.Control):Text . 
		   
		IF cEmail > "":U THEN 
		    IF INDEX (cEmail, "@":U) = 0 THEN DO:
                Consultingwerk.Util.MessageFormHelper:ShowMessage ("Email address should contain at least @.",
                                                                   Consultingwerk.Windows.Util.Forms.MessageFormImages:ImageError) .
    		  
    		    e:Cancel = TRUE . 
    		END.
	END METHOD .
END CLASS.