The Customer + .NET WPF GridView User Control sample CustGridWPF.sln shows a WPF user control used by a Dialog System application. The sample shows how a WPF user control can be hosted, how it can have methods invoked and how it can fire events, which can be consumed in the Dialog System application, as illustrated in the following diagram:
There are two key points about WPF shown in this sample:
The sample is based on the original CustGrid sample from Dialog System. It has two projects: one is the original CustGrid sample and the second contains the code for a simple WPF DataGrid control written in COBOL. The DataGrid control is similar to the control used in the Customer samples (Customer +.NET User Control and Customer + .NET WinForm). Here, in this sample, the DataGrid is a WPF user control.
In this sample, the control is not a complete implementation of a grid control and the application is not a complete implementation. The sample is designed to illustrate the principles only.
The WPFCustGrid project contains the original CustGrid project from Dialog System.
CustGrid.gs is the screenset, which now contains the DataGrid control instead of the original ActiveX grid control. In the same way as before, Dialog System communicates with the native code gridctrl.cbl, using callouts and callbacks.
GridCtrl.cbl handles the events generated by the DataGrid control. It invokes the COM code in the same way as it invoked the ActiveX code before. For example, the Delete-A-Row Section handles the delete-row event and invokes the COM code, as follows:
INVOKE RowSet "GetSelect" USING theRow RETURNING Numeric-Value INVOKE RowSet "Remove" USING Numeric-Value
Where RowSet is defined in the COM interface for the WPF user control in ControlInterface.cbl, which is described later.
The WPFGridViewUserControl project contains two user controls: one WPF and one Windows Forms. Both controls are needed because the WPF user control is hosted as a Windows Forms user control (which is then wrapped as an ActiveX control). The content is actually a WPF control, but it is handled as a Windows Forms user control, just as in the sample Customer + .NET User Control.
To see the two controls, double-click:
The project contains the following to complete the implementation:
The project is registered for COM interop. In addition the COMRegister() method puts the appropriate entries into the registry so that ActiveX containers see this as a control. This method is covered in more detail later.
ControlInterface.cbl defines the interface that exposes the methods and properties of the control to COM:
interface-id MicroFocus.VisualCOBOL.IWPFSampleGridView attribute Guid("77BECD4D-5504-442D-9DDA-A78C30ADF6A9") attribute InterfaceType(type ComInterfaceType::InterfaceIsDual) attribute ComVisible(true). method-id get property RowSet. ...
GridViewControl.cbl contains the class that defines the behavior of the DataGrid control. Its main task is to replicate the behavior of the old ActiveX control in the new DataGrid control.
GridViewControl.cbl includes the following code of interest:
Defines the WPFSampleGridView class, which inherits from the Windows Forms UserControl class and implements the IWPFSampleGridView interface declared in ControlInterface.cbl. It also implements the ISerializable interface, which enables the class to control its serialization behavior.
Class-id WPFSampleGridView inherits type System.Windows.Forms.UserControl implements type System.Runtime.Serialization.ISerializable type MicroFocus.VisualCOBOL.IWPFSampleGridView
Enable the class to be serialized. This attribute is required even if though the class also implements the ISerializable interface to control the serialization process.
attribute Serializable()
Make the managed class visible to COM. Exposes the class to COM:
attribute ComVisible(true)
Specify the ProgID for the COM object. This is a human-readable version of the class identifier (CLSID) used to identify COM/ActiveX objects:
attribute ProgId("WPFSampleGridView")
Generate a class interface that supports early and late binding:
attribute ClassInterface(type ClassInterfaceType::None)
Specify the interface ISampleGridView as the default interface to expose to COM:
attribute ComDefaultInterface (type of MicroFocus.VisualCOBOL.IWPFSampleGridView)
Identify the IGridViewEvents as the interface to be exposed as COM event sources for the library WindowsFormsControlLibrary1.dll (which is built by the GridViewUserControl project):
attribute ComSourceInterfaces (type of MicroFocus.VisualCOBOL.IWPFGridViewEvents)
Specify an explicit GUID. This is useful during the debugging phase, as it avoids a new GUID being generated each time you build and register:
attribute Guid("E0A41600-4531-4E55-9B24-6D2F1CF8B106")
Create an observable collection of CustomerOrder objects, which enables the backing data to be updated when the user interface changes (such as when the user edits the data):
*> Create an observable collection of CustomerOrder *> objects so that the data grid receives notifications *> such as add, delete in order to refresh the list 01 _customerOrders type ObservableCollection[type CustomerOrder] value new ObservableCollection[type CustomerOrder] public property as "CustomerOrders".
The SampleGridView class provides the following methods and delegate definitions:
This method adds an entry to the Registry for the specified object. It sets the appropriate entries to register the object as an ActiveX, so that ActiveX containers see this as a control. This enables Dialog System to list the ActiveX as one of the controls available for import.
The project property Register for COM Interop registers the object as COM, but does not register it as ActiveX.
The reverse of the COMRegister() method.
These methods create an instance of the WPFSampleGridView. The default New() method initializes the instance and adds the specified data by invoking the appropriate methods: OnSelectionChanged(), OnCellEditEnding() and OnSourceUpdated().
Handles the OnSourceUpdated event, determines the row updated and invokes the FireOnChanged() method.
Handles the OnCellEditEnding event and invokes the FireOnChanged() method.
Handles the OnSelectionChanged event, determines the row and invokes the FireRowSelected() method.
This is used as part of serialization of the control. However, this sample does not have anything to persist so this method is unused.
Implements the interface IWPFSampleGridView. Creates an instance of the row.
This enables the Windows Forms user control to access the WPF DataGrid user control.
method-id. get property OrderGrid. procedure division returning thegrid as type System.Windows.Controls.DataGrid. set thegrid to self::wpfUserControl1::OrdersGrid
Handles the cell editing event.
method-id OrdersGridView_CellEndEdit final private. procedure division using by value sender as object e as type System.EventArgs.
Defines the delegates for our events:
01 OnRowSelected type RowSelectedEventHandler event public. 01 OnRowDeleted type RowDeletedEventHandler event public. 01 OnChanged type CellEditEndingHandler event public. ... delegate-id RowSelectedEventHandler. delegate-id RowDeletedEventHandler. delegate-id CellEditEndingHandler.
IWPFGridViewEvents.cbl defines an interface for the events. The interface has the ComInterfaceType.InterfaceIsIDispatch attribute, which restricts callers to late binding.
interface-id MicroFocus.VisualCOBOL.IWPFGridViewEvents attribute Guid("3DC45DA1-A580-4280-A2DB-7B6A266032AE") attribute InterfaceType (type ComInterfaceType::InterfaceIsIDispatch) attribute ComVisible(true).
The interface defines a method for each event, and assigns each event a COM dispatch identifier (DispId), as follows:
method-id OnRowSelected attribute DispId(29). ... method-id OnRowDeleted attribute DispId(18). ... method-id OnChanged attribute DispId(6).
The events correspond to the delegates defined in the WPFSampleGridView class in GridViewControl.cbl.
Note, this interface is not implemented in our solution.
CustomerOrder.cbl defines the CustomerOrder class, which contains methods to create and initialize an instance of a customer order, and to return an array of customer orders.
The CustomerOrder class demonstrates a key concept in WPF, data binding. It demonstrates how the data can be associated with the user interface.
The CustomerOrder class maps to a Customer Order group item in the data block, so part of the sample gets data from the data block and creates a list of Customer Orders. This object is then associated with the WPF DataGrid, which renders the control to match the data in the list. The object is defined in GridViewControl.cbl, as the type ObservableCollection.