Adding a custom control to a form

In the shipped product for 6.1.4 and 6.2.1, the example to add a custom control to a form, in the documentation does not work. This article will explain another way of achieving the same thing.

I first made some modifications to the supplied example. The line of code that actually adds the control to the grid has been replaced by a call to a new static method in the CustomControlManager.

LOCAL CURRENT.FORM, TAB.CONTAINER, CUSTOM.USER.CONTROL LOCAL LAYOUT.HANDLE, DISP.DEBUG, ERR, CUSTOM.CONTROL.NAME **** *** Added these variables LOCAL ASSEMBLY_NAME, TYPE, METHOD_NAME, PARAMETERS, RETVAL, STATUS, STATUSDESC *** ****** DISP.DEBUG = 1 ; * Change this to a 1 if you want to see the error messages CUSTOM.CONTROL.NAME = "CustomUserControl" * * This is not required in order to create the custom control; it is here purely for * example sake. * * Get the handle to the current form. If this paragraph is run on a tab, the * handle to the current form is returned. * CURRENT.FORM = OBJHANDLE(@FORM) IF DISP.DEBUG THEN DISP 4, "Handle to the current form is ":CURRENT.FORM * * Before we create the custom control, first check to see if it already exists. If it exists, do not create it again. * CUSTOM.USER.CONTROL = OBJHANDLE(CUSTOM.CONTROL.NAME) IF DISP.DEBUG THEN DISP 4, "CUSTOM.USER.CONTROL = ":CUSTOM.USER.CONTROL IF CUSTOM.USER.CONTROL # "" THEN EXIT * * Create the custom control. The first parameter is the name of the UCR definition, the second is the parent (which, in this * case is the current form), the third is the name of the object, the last two parameters are any attributes and values * that need to be set on the object after it has been created. * CUSTOM.USER.CONTROL = OBJCREATE("CustomUserControl",@FORM, CUSTOM.CONTROL.NAME, "", "") IF DISP.DEBUG THEN DISP 4, "Custom user control handle is ":CUSTOM.USER.CONTROL * * The control has been created. Now we need to add it to the visual tree of the form. In order to do this we need to * find the part in the visual tree that has the name PART_SBFormLayoutControl. If you look at the visual tree in snoop, you * should be able to find it. * ****************************************************************** *** Added the following code to call the AddChildToForm method *** ****************************************************************** LAYOUT.HANDLE = GETATTR(@FORM,"FindVisualChildByName":@VM:"PART_SBFormLayoutControl") IF DISP.DEBUG THEN DISP 4, "LAYOUT.HANDLE = ":LAYOUT.HANDLE * * We have the handle to the layout control, which happens to be a grid. Now add the custom control to the children. ASSEMBLY_NAME = "CustomThemeLibrary" TYPE = "SBXACustomControlExamples.CustomControlManager" METHOD_NAME = "AddChildToForm" PARAMETERS = LAYOUT.HANDLE:@VM:"@FORM":@VM:CUSTOM.USER.CONTROL RETVAL = "" STATUS = "" STATUSDESC = "" * CALL SB.DISP(4, "About call AddChildToForm") CALL SB.CALL.STATIC.METHOD("", ASSEMBLY_NAME, TYPE, METHOD_NAME, PARAMETERS, RETVAL, STATUS, STATUSDESC) ****************************************** ****************************************** ****************************************** * remove this line as it has been replaced by a call to the static method AddChildToForm ERR = SETATTR(LAYOUT.HANDLE, "Children.Add", CUSTOM.USER.CONTROL) IF DISP.DEBUG THEN DISP 4, "After of Children.Add ERR = ":STATUSDESC * * And we should see the control on the form now. * IF DISP.DEBUG THEN DISP 4, "Custom control loaded." I added a method to the CustomControlManager AddChildToForm which is called with three parameters, the handle to the layout control, a reference to the current form (@FORM) and the handle to the custom control. The two handles are strings which are obviously not valid .Net handles. These strings are resolved into true object references by a call to ObjectManager. public static string AddChildToForm(string layout, string formHandle, string controlHandle) {   // As opposed to getting the handle to the layout control on the server, you can do it all on the client // by passing @FORM and resolving it on the client. string iSBForm = SBPlus.Current.ResolveServerTokens(formHandle); if (string.IsNullOrEmpty(iSBForm) || iSBForm == "0") return ("No current form."); // Use the string version of the object handle to get a reference to the custom control. ISBObject realObject = ObjectManager.Get(controlHandle).RealObject; UIElement uiElement = null; if (realObject is UserObjectReference) {      uiElement = (realObject as UserObjectReference).UserObject as UIElement; if (uiElement == null) return ("Object was not a UIElement."); }   if (string.IsNullOrEmpty(layout)) return ("No layout control."); // Use the string version of the layout control (in this case a grid) // to get a reference to the actual grid object. ISBObject layoutObject = ObjectManager.Get(layout).RealObject; if (layoutObject is UserObjectReference) {      Grid grid = (layoutObject as UserObjectReference).UserObject as Grid; if (grid == null) return ("No Layout control found."); // and finally add the control. grid.Children.Add(uiElement); // Even if SB use a GRID as layout, component must be absolutly positionned          if (uiElement is Control) {         // position the new uiElement at 250 Left, 150 Top from then current Form Thickness m = new Thickness(250,150,0,0); (uiElement as Control).Margin = m         // we can/must fix width and height of the element (uiElement as Control).Width = 100; (uiElement as Control).Heigth = 150; }   }    return (string.Empty); }