Frequently Asked Questions
Frequently Asked Questions (exontrol)
ALL.1:
Most of our UI components provide a Template page that's accessible in design mode. No matter what programming language you are using, you can have a quick view of the component's features using the WYSWYG Template editor.
  • Place the control to your form or dialog. 
  • Locate the Properties item, in the control's context menu, in design mode. If your environment doesn't provide a Properties item in the control's context menu, please try to locate in the Properties browser.
  • Click it, and locate the Template page.
  • Click the Help button. In the left side, you will see the component, in the right side, you will see a x-script code that calls methods and properties of the control.

The following picture shows the control's Template page:

where the running panel shows the control's itself once the x-script ( from xcript panel ) code is executed. You can use the Exontrol's eXHelper tool to get more x-script code for different how to questions. Also using the eXHelper you can generate the source code in different programming languages from VB6 to C++. 

The control's Template page helps user to initialize the control's look and feel in design mode, using the x-script language that's easy and powerful. The Template page displays the control  on the left side of the page. On the right side of the Template page, a simple editor is displayed where user writes the initialization code. The control's look and feel is automatically updated as soon as the user types new instructions. The Template script is saved to the container persistence ( when Apply button is pressed ), and it is executed when the control is initialized at runtime. Any component that provides a WYSWYG Template page, provides a Template property. The Template property executes code from a string ( template string ).  

The Template/x-script code is a simple way of calling control/object's properties, methods/events using strings. Exontrol owns the x-script implementation in its easiest way and it does not require any VB engine to get executed. Our simple rule is using the component alone without any other dependency than the Windows system.

The Template/x-script syntax in BNF notation is defined like follows:

<x-script> := <lines>
<lines> := <line>[<eol> <lines>] | <block>
<block> := <call> [<eol>] { [<eol>] <lines> [<eol>] } [<eol>]
<eol> := ";" | "\r\n"
<line> := <dim> | <createobject> | <call> | <set> | <comment>
<dim> := "DIM" <variables>
<variables> := <variable> [, <variables>]
<variable> := "ME" | <identifier>
<createobject> := "CREATEOBJECT(`"<type>"`)"
<call> := <variable> | <property> | <variable>"."<property> | <createobject>"."<property>
<property> := [<property>"."]<identifier>["("<parameters>")"]
<set> := <call> "=" <value>
<property> := <identifier> | <identifier>"("[<parameters>]")"
<parameters> := <value> [","<parameters>]
<value> := <boolean> | <number> | <color> | <date> | <string> | <createobject> | <call>
<boolean> := "TRUE" | "FALSE"
<number> := "0X"<hexa> | ["-"]<integer>["."<integer>]
<digit10> := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<digit16> := <digit10> | A | B | C | D | E | F
<integer> := <digit10>[<integer>]
<hexa> := <digit16>[<hexa>]
<color> := "RGB("<integer>","<integer>","<integer>")"
<date> := "#"<integer>"/"<integer>"/"<integer>" "[<integer>":"<integer>":"<integer>"]"#"
<string> := '"'<text>'"' | "`"<text>"`"
<comment> := "'"<text>

where:

<identifier> indicates an identifier of the variable, property or method, and should start with a letter.
<type> indicates the type the CreateObject function creates, as a progID
<text> any string of characters

The Template or x-script is composed by lines of instructions. Instructions are separated by "\n\r" ( newline characters ) or ";" character. The ; character may be available only for newer versions of the components

An x-script instruction/line can be one of the following:

  • Dim variable[, variable, ...] declares the variables in the context. Multiple variables are separated by commas. ( Sample: Dim h, h1, h2 )
  • variable = [object.][property/method( arguments ).]property/method( arguments ) assigns the result of the property/method call to the variable.  ( Sample: h = InsertItem(0,"New Child") )
  • [object.][property/method( arguments ).]property( arguments ) = value assigns the value to the property. ( Sample: Columns.Add(`Hidden`).Visible = False )
  • [object.][property/method( arguments ).]property/method( arguments ) invokes the property/method. ( Sample: Columns.Add(`Column`) )
  • {context } delimits the object's context. The properties/fields or methods called between { and } are related to the last object returned by the property/method prior to { declaration. (Sample: Nodes{Add(`Child 1`);Add(`Child 2`)} )
  • . delimits the object than its property or method. (Sample: Nodes.Add(`Element`), or Nodes.Add(`Element`) and Nodes{Add(`Element`)} are equivalents )

where

  • variable is the name of a variable declared with Dim command or previously defined using the TemplateDef method.
  • property is the name of a property/field of the current object in the current context.
  • method is the name of a method of the current object in the current context.
  • arguments include constants and/or variables and/or property/method calls separated by comma character.
  • object can be a variable of an Object type, Me or CreateObject call.

The x-script may uses constant expressions as follow:

  • boolean expression with possible values as True or False. The True value is equivalent with -1, while False with 0. (Sample: Visible = False )
  • numeric expression may starts with 0x which indicates a hexa decimal representation, else it should starts with digit, or +/- followed by a digit, and . is the decimal separator. Sample: 13 indicates the integer 13, or 12.45 indicates the double expression 12,45 ( Sample: BackColor = 0xFF0000 ) 
  • date expression is delimited by # character in the format #MM/dd/yyyy hh:mm:ss#. For instance, #31/12/1971# indicates the December 31, 1971 ( Sample: Chart.FirstVisibleDate = #1/1/2001# )
  • string expression is delimited by " or ` characters. If using the ` character, please make sure that it is different than ' which allows adding comments inline. Sample: "text" or `text` indicates the string text, while the ' text , specifies the comment text ( Sample: Columns.Add(`Column`).HTMLCaption = "<b>caption</b>" )

Also , the template or x-script code may support general functions as follows:

  • Me property indicates the original object, and it is defined as a predefined variable.  ( Sample: Me.Nodes.Add(`Element`) )
  • RGB(R,G,B) property retrieves an RGB value, where the R, G, B are byte values that indicates the Red Green Blue bytes for the color being specified. ( Sample: Nodes.Add(`Root 1`).BackColor = RGB(255,0,0) )
  • LoadPicture(file) property loads a picture from a file and returns a Picture object required by the picture properties. (Sample: Picture = LoadPicture(`C:\exontrol\images\auction.gif`)
  • CreateObject(progID) property creates and retrieves a single uninitialized object of the class associated with a specified program identifier. For instance, the following code creates an ADOR.Recordset and pass it to the control using the DataSource property:
    Dim rs
    ColumnAutoResize = False
    rs = CreateObject("ADOR.Recordset")
    {
    	Open("Orders","Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program Files\Exontrol\ExGrid\Sample\SAMPLE.MDB", 3, 3 )
    }
    DataSource = rs
    

Here's a very simple template/x-script sample:

Columns
{
	Add("Column 1")
	Add("Column 2")
}
Items
{
	CellValue(AddItem("Item 1"),1) = "SubItem 1"
	CellValue(AddItem("Item 2"),1) = "SubItem 2"
}

The sample calls twice the Add method of the Columns object, and in the Items context it calls the AddItem property and pass the result to the CellValue property as the first parameter.

The user can display the list of methods and properties of the control by pressing the CTRL + SPACE key, in the Template's editor. Let's say that we have the exTree's Template page displayed. For instance, the following sample is a Template script that adds few columns and items to an exTree control:

BackColor = RGB(255,255,255)			'Changes the control's background color.
ForeColor = RGB(0,0,255)				'Changes the control's foreground color.
MarkSearchColumn = False				'Hides the mark of the searching column.
Columns									'Calls the Columns property, to add new columns.
{											'Beginning the context of Columns object. The context is exTree.Columns
	"Column 1"					'Adds a new column "Column 1".
	Add("Column 2")				'Adds a new column "Column 2", and gets the last Column object. 
	{											'Opens the context of the Column object. The context is exTree.Columns.Column
		HTMLCaption = "Caption "<b>2</b>"	'Assigns an HTML caption to last added column.
		Position = 0													'Changes the position. 
	}											'Ends the context of the Column object
}										'Ends the context of the Columns object
Items									'Calls the Items property, and opens the context of the Items object
{										'Opens the context of the Items object. The context is exTree.Items
	Dim h									'Declares the 'h' variable for later use
	h = AddItem("Root")			'Adds a new item, and assigns the handle of the item to the 'h' variable
	InsertItem(h,,"Child")		'Inserts a child item.
	ExpandItem(h) = True					'Expands an item.
}										'Ends the context of Items object

How can I check this sample?

  • Creates a new project
  • Adds an exTree instance to the project's form
  • Select the exTree component in design mode
  • Select the 'Properties' item of the exTree's context menu.
  • Select the 'Template' page
  • Copy and Paste the sample in the Template's editor that's on the right side of the page.
  • Presses the 'Apply' button.
  • Closes the 'Property Pages' dialog
  • Run your project
Some controls provide the AllowCopyTemplate property which can be used to generate the x-script code from the control's content.
ALL.2:

On .NET Framework the exontrol.NETObjectTemplate object ( part of the exontrol.NETHost.dll ) can be used  to run / execute x-script code for .NET assemblies/objects. For instance: (new exontrol.NETObjectTemplate(this)).Template = "Dim c; c = CreateObject(`System.Windows.Forms.TextBox, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`){Text=`Edit`;Dock=5}; Controls.Add(c)"; adds a new control of TextBox type to this.Controls collection

The Template/ x-script code is a simple way of calling control/object's properties, methods/ events using strings. Exontrol owns the x-script implementation in its easiest way and it does not require any VB engine to get executed. Our simple rule is using the component alone without any other dependency than the Windows system.

The Template/x-script syntax in BNF notation is defined like follows:

<x-script> := <lines>
<lines> := <line>[<eol> <lines>] | <block>
<block> := <call> [<eol>] { [<eol>] <lines> [<eol>] } [<eol>]
<eol> := ";" | "\r\n"
<line> := <dim> | <createobject> | <call> | <set> | <comment>
<dim> := "DIM" <variables>
<variables> := <variable> [, <variables>]
<variable> := "ME" | <identifier>
<createobject> := "CREATEOBJECT(`"<type>"`)"
<call> := <variable> | <property> | <variable>"."<property> | <createobject>"."<property>
<property> := [<property>"."]<identifier>["("<parameters>")"]
<set> := <call> "=" <value>
<property> := <identifier> | <identifier>"("[<parameters>]")"
<parameters> := <value> [","<parameters>]
<value> := <boolean> | <number> | <color> | <date> | <string> | <createobject> | <call>
<boolean> := "TRUE" | "FALSE"
<number> := "0X"<hexa> | ["-"]<integer>["."<integer>]
<digit10> := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<digit16> := <digit10> | A | B | C | D | E | F
<integer> := <digit10>[<integer>]
<hexa> := <digit16>[<hexa>]
<color> := "RGB("<integer>","<integer>","<integer>")"
<date> := "#"<integer>"/"<integer>"/"<integer>" "[<integer>":"<integer>":"<integer>"]"#"
<string> := '"'<text>'"' | "`"<text>"`"
<comment> := "'"<text>

where:

<identifier> indicates an identifier of the variable, property or method, and should start with a letter.
<type> indicates the type the CreateObject function creates, as the assembly-qualified name of the type to create.
<text> any string of characters

The Template / x-script is composed by lines of instructions. Instructions are separated by "\r\n" ( new line characters ) or ";" character. The TemplateThrowError property specifies whether the control fires an exception/error when the Template call fails. The TemplateError / TemplateException gets the error if the Template calls fails. The TemplateResult property returns the result of the last instruction into a Template call, as a NETObjectTemplate object.

An x-script instruction/line can be one of the following:

  • Dim variable[, variable, ...] declares the variables in the context. Multiple variables are separated by commas. The SetTemplateDef method can declare new variables to be available for the main context. ( Sample: Dim h, h1, h2 )
  • variable = [object.][property/method( arguments ).]property/method( arguments ) assigns the result of the property/method call to the variable. ( Sample: h = Nodes.Add(`Node`) )
  • [object.][property/method( arguments ).]property( arguments ) = value assigns the value to the property. ( Sample: Nodes.Add(`Node`).BackColor = RGB(255,0,0) )
  • [object.][property/method( arguments ).]property/method( arguments ) invokes the property/method. ( Sample: Nodes.Add(`Node`) )
  • {context } delimits the object's context. The properties/fields or methods called between { and } are related to the last object returned by the property/method prior to { declaration. (Sample: Nodes{Add(`Child 1`);Add(`Child 2`)} )
  • . delimits the object than its property or method. (Sample: Nodes.Add(`Element`), or Nodes.Add(`Element`) and Nodes{Add(`Element`)} are equivalents )

where

  • variable is the name of a variable declared with Dim command or previously defined using the SetTemplateDef method.
  • property is the name of a property/field of the current object in the current context.
  • method is the name of a method of the current object in the current context.
  • arguments include constants and/or variables and/or property/method calls separated by comma character.
  • object can be a variable of an Object type, Me or CreateObject call.

The x-script uses constant expressions as follows:

  • boolean expression with possible values as True or False. The True value is equivalent with -1, while False with 0. (Sample: Visible = False )
  • numeric expression may starts with 0x which indicates a hexa decimal representation, else it should starts with digit, or +/- followed by a digit, and . is the decimal separator. Sample: 13 indicates the integer 13, or 12.45 indicates the double expression 12,45. ( Sample: BackColor = 0xFF0000 )
  • date expression is delimited by # character in the format #MM/dd/yyyy hh:mm:ss#. For instance, #31/12/1971# indicates the December 31, 1971 ( Sample: Chart.FirstVisibleDate = #1/1/2001# )
  • string expression is delimited by " or ` characters. If using the ` character, please make sure that it is different than ' which allows adding comments inline. Sample: "text" or `text` indicates the string text, while the ' text , specifies the comment text. ( Sample: Text = "caption" )

Also , the template or x-script code supports general functions as follows:

  • Me property indicates the original object, and it is defined as a predefined variable.  ( Sample: Me.Nodes.Add(`Root 1`) )
  • RGB(R,G,B) property retrieves an RGB value, where the R, G, B are byte values that indicates the Red Green Blue bytes for the color being specified. ( Sample: Nodes.Add(`Root 1`).BackColor = RGB(255,0,0) )
  • LoadPicture(file) property loads a picture from a file and returns a Picture object required by the picture properties. (Sample: BackgroundImage = LoadPicture(`C:\exontrol\images\auction.gif`)
  • CreateObject(assemblyQualifiedName) property creates an instance of the specified type using that type's default constructor. The assemblyQualifiedName indicates the assembly-qualified name of the type to get. See AssemblyQualifiedName. If the type is in the currently executing assembly or in Mscorlib.dll, it is sufficient to supply the type name qualified by its namespace. ( Sample: "CreateObject(`System.Windows.Forms.TabPage, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`){Text = `Page`;UseVisualStyleBackColor = True}" )
ALL.3:
The most probably is missing the CODEBASE HTML tag, that informs the IE browser where getting the object with specified CLASSID, when it is not locally installed.

For instance, using the form <OBJECT classid="clsid:CD481F4D-2D25-4759-803F-752C568F53B7" id="G2antt1"></OBJECT> is not sufficient, as it must include the CODEBASE attribute, so the IE browser knows how to handle the situation when the component is not installed on the client machine. 

In conclusion, you need to add the CODEBASE attribute as in the following sample 

<OBJECT 
	CLASSID="clsid:CD481F4D-2D25-4759-803F-752C568F53B7" 
	CODEBASE="http://yoursever/ExG2antt.dll"
	ID="G2antt1"
</OBJECT>

This way, when IE browser loads the html page do the following:

  • check if the object with the specified CLASSID is locally installed, then the CODEBASE attribute is ignored and go further.
  • if the object with the specified CLASSID is not installed, it looks for CODEBASE, to get the file where the specified object is, loads and installs it.
ALL.4:
A licensed ActiveX control does not load properly in an Internet Explorer HTML page if the computer is not licensed to use the control. To use licensed controls in an HTML page on a non-licensed computer, you must generate a license package file (LPK). The LPK file contains the run-time licenses for licensed controls in the HTML page. Please follow the following steps in order to add the component to your HTML page:
  • Build the lpk file using the LPK tool. You need to run it on the computer where you have installed a licensed control.
  • Insert the an <OBJECT> tag for the License Manager object before any other <OBJECT> tags like follows: 

<OBJECT CLASSID = "clsid:5220cb21-c88d-11cf-b347-00aa00a28331" VIEWASTEXT>
    <PARAM NAME="LPKPath" VALUE="relative URL to .LPK file">
</OBJECT>
Insert the <OBJECT> tag for your licensed control afterward like:
<OBJECT CLASSID="clsid:F26C97E5-3E86-4CE4-935B-A997AB3DDBE4" 
	ID="FileView1" HEIGHT="200" WIDTH="400" CODEBASE="exfileview.cab">
</OBJECT>

For instance, if you need to insert an ExFileView component to your HTML page, you need insert tags like follows:

<OBJECT CLASSID = "clsid:5220cb21-c88d-11cf-b347-00aa00a28331" VIEWASTEXT>
	<PARAM NAME="LPKPath" VALUE="exfileview.lpk">
</OBJECT>
<OBJECT CLASSID="clsid:F26C97E5-3E86-4CE4-935B-A997AB3DDBE4" 
	ID="FileView1" HEIGHT="200" WIDTH="400" CODEBASE="exfileview.cab">
</OBJECT>

If you followed the steps, but the component doesn't show up in your HTML page, you have to make sure that the CLSIDs used are good, and also you have used the right paths for lpk and cab file too. A simple way to check for those paths, is to copy the path to your browser's address bar and to hit ENTER key. If the browser is able to locate the file, then your HTML page should load ok.   

See Also: HOWTO: Use Licensed ActiveX Controls in Internet, LPK tool, How do I build a CAB file?
ALL.5:
To fix it, you have to change the font of the control, from Arial, 8 to another font. By default, the control's font is Arial. You can do the following test: create an empty form, add a label control, select font the Arial, 8 in the label control, and change the label's caption to "Wheel". You will be able to see the same problem.
ALL.6:
Controls marked as non-creatable are usually tailored to specific development environments. Controls in Microsoft Forms ( fm20.dll ) for example are of this kind ). For instance, the Forms.ComboBox object definition is :
[
  uuid(8BD21D30-EC42-11CE-9E0D-00AA006002F3),
  helpcontext(0x001e8660),
  noncreatable,
  control
]
coclass ComboBox {
    [default] interface IMdcCombo;
    [default, source] dispinterface MdcComboEvents;
};

The following sample inserts a Forms.ListBox control to the exGrid component.

With Grid1
    .BeginUpdate
        With .Columns
            .Add "Column 1"
        End With
        With .Items
            Dim h As HITEM
            h = .InsertControlItem(, "Forms.ListBox.1", "")
            
            With .ItemObject(h)
                .AddItem 1
                .AddItem 2
                .AddItem 3
                .AddItem 4
                .AddItem 5
            End With
            .ItemHeight(h) = 128
        End With
    .EndUpdate
End With

If you need to browse the properties of created ActiveX control at runtime, you can use the exPropertiesList control like follows:

With PropertiesList1
    .ColumnAutoResize = False
    .HeaderVisible = True
    .Select Grid1.Items.ItemObject(h)
End With

You can display the list of events that created ActiveX control is firing using the ItemOleEvent event like follows:

Private Sub Grid1_ItemOleEvent(ByVal Item As EXGRIDLibCtl.HITEM, ByVal Ev As EXGRIDLibCtl.IOleEvent)
    Debug.Print Ev.Name
End Sub
ALL.7:
Each control that handle icons provides a property called ShowImageList. The ShowImageList property specifies a value that indicates whether the control's images panel is visible or hidden. If you are using the MSVC environment it's possible that the control's images panel being visible on the desktop, so all that you need to do is to minimize all windows, and you will be able to locate the control's images panel.

An .ICO file may contain multiple configurations/resolutions for the same picture. The component has no control of what resolution will be used when displaying the icon in the control's client area, therefore it is recommended to drag only 16x16 icons (files, for small icons ), else all of the following could happen:

  • Your resource will be larger 
  • Your resource contains data that's possible being never used.
  • The component is possible to stretch an larger resolution icon to 16x16 area and so the result on the display will not be how you expect.
So before dragging the icon files to the control's images panel please check each resolution for each icon. You can use the MSDEV environment to load an icon ( File\Open, Select the Type of Images Files, and Open as: Auto ). Once that you have loaded the icon in the MSDEV editor, you can delete a resolution using the Image\Delete Device Image item menu.
ALL.8:
On Windows XP, we have the confirmation that hImageList property of MSComCtl.ImageList object returns an invalid handle, and it cannot be used by ImageList-related API functions. In order to fix the problem please use the following function to attach an images list at runtime ( download here the VB sample ):
Private Declare Function ImageList_Create Lib "comctl32.dll" _
    (ByVal cx As Long, ByVal cy As Long, ByVal flags As Long, ByVal _ 
    initial As Long, ByVal grow As Long) _
    As OLE_HANDLE
Private Declare Function ImageList_Destroy Lib "comctl32.dll" _
    (ByVal handle As OLE_HANDLE) _
    As Boolean
Private Declare Function ImageList_ReplaceIcon Lib "comctl32.dll" _
    (ByVal handle As OLE_HANDLE, ByVal i As Long, ByVal hIcon As OLE_HANDLE) _
    As Long

Private Sub AttachImageList(ByVal ctrl As Object, ByVal msImageList As Object)
    Dim img As Object
    Dim h As OLE_HANDLE
    h = ImageList_Create(16, 16, &H21, 0, 0)
    For Each img In msImageList.ListImages
        ImageList_ReplaceIcon h, -1, img.Picture.handle
    Next
    ctrl.Images h
    ImageList_Destroy h
End Sub

It makes no sense to do this in VFP, because VFP delivers both controls (mscomctl.ocx and comctl32.ocx) for redistribution. So i used the comctl32.imagelist.1 ("old") instead of of mscomctlLib.imagelist.2 ("new") which totally solved the problem. Because both controls can be used together on a form (if one delivers both ocx to enduser) there is no problem even if one has to use some of the newer mscomtcl objects (like the progressbar). Using comctl32 was proved to fully function with XP SP2. So for your knowledgebase it would be quite enough and rather useful to mention that if one wants to use an imagelist as "picture-deliverer" for exontrols and the target OS can be WinXP, one must use the "older" comctl32.oxc and NOT the mscomctl.oxc Object. If both objects are registered to the system both show up on the extras/options/objects list in VFP as: 

Microsoft ImageList Control 6.0 (SP6) --> mscomctl.ocx 
Microsoft ImageList Control 5.0 (SP2) --> comctl32.ocx

Only the last will work correct with XP. As the usable APIs of both version are identical for VFP-users, it is simple replacing and renaming the object to solve the problem. Thanks to Michael Schwing, LOGO Datensysteme GbR who provided the VFP note.

See also:
ALL.9:
All parent windows of the control must include styles like WS_CLIPCHILDREN and WS_CLIPSIBLINGS, else this problem may occur. For instance, if you have the control on a wizard page, these styles must be applied to the wizard window like described bellow. You can use the Spy++ tool ( that's installed by your DevStudio ) in order to find out what styles a specified window contains. For instance, the following sample handles the  WM_INITDIALOG message or OnInitDialog function in order to append the WS_CLIPCHILDREN and WS_CLIPSIBLINGS styles:
BOOL CWizard::OnInitDialog()
{
	ModifyStyle( 0, WS_CLIPCHILDREN | WS_CLIPSIBLINGS );
	return CPropertySheet::OnInitDialog();
}

The WS_CLIPCHILDREN style excludes the area occupied by child windows when you draw within the parent window. Used when you create the parent window. The WS_CLIPSIBLINGS style clips child windows relative to each other. For more information on these styles please consult your MSDN library.

Generally, the VB forms, VFP screens include these styles. In NET projects or C++ applications, these styles should be set by the user, using properties like Clip Children, Clip Siblings.  

For instance, if the control is hosted by an ATL composite control you can call the following statement in the OnInitDialog event handler:

GetDlgItem( IDC_CONTROL ).ModifyStyle(0, WS_CLIPCHILDREN | WS_CLIPSIBLINGS );

where the IDC_CONTROL is the resource identifier of the control. 

Please pay attention to the situation when the control is hosted by another control such of composition control, when it adds a "hidden" window as being the parent window for the control, such as AtlAxWinLic80, and so the WS_CLIPCHILDREN and WS_CLIPSIBLINGS styles must be set for this window too, like in the above sample. In other cases, you can use the GetParent API function to get the parent window of the control. You can use ModifyStyle or SetWindowLong(GWL_STYLE) API functions to change the styles for a certain window.

See also: I have your control on my VC dialog and it flickers when I click the control. Any suggestion?

ALL.10:
The control's font can be changed only if the control provides a property called Font. For instance, the following samples shows how to change the font for exEdit control, but the methods are the same for other controls too.
  1. Creating a Font object and passing it to the Font property like in the following VB sample:
    Dim f As New StdFont
    f.Name = "Arial"
    f.Size = 14
    Edit1.Font = f
  2. Calling the Name property of the Font object like in the following VB sample:
    With Edit1
        With .Font
            .Name = "Arial"
            .Size = 12
        End With
        .Refresh
    End With
  3. Using the Template property ( most of our GUI components provides a Template property ), with a template string like:
    Font
    {
    	Name = "Arial"
    	Size = 14
    }
    Refresh

    so the VB sample looks like:

    Dim s As String
    s = "Font" + vbCrLf
    s = s + "{" + vbCrLf
    s = s + "   Name = ""Arial""" + vbCrLf
    s = s + "   Size = 14" + vbCrLf
    s = s + "}" + vbCrLf
    s = s + "Refresh" + vbCrLf
    Edit1.Template = s

    If your environment is not able to handle Font objects ( the Font objects are system object and exist in all Windows systems ) , this the best way to set the control's font at runtime.

Even if you are using other controls to change font, you need to make sure that a Refresh method exists, else you could use alternatives like BeginUpdate and EndUpdate methods, or something that's related. Please see also the C++ alternative here.

For instance, if a property exports an IFontDisp interface and you are using the .NET environment you can use the GetIFontFromFont method of the AxHost object like shown in the following samples:

The following VB.NET sample changes the font for the focused item:

With AxTree1.Items
    .ItemFont(.FocusItem) = IFDH.GetIFontDisp(AxTree1.Font)
    With .ItemFont(.FocusItem)
        .Name = "Comic Sans MS"
        .Bold = True
    End With
End With
AxTree1.Refresh()

where the IFDH class is defined like follows:

Public Class IFDH
    Inherits System.Windows.Forms.AxHost

    Sub New()
        MyBase.New("")
    End Sub

    Public Shared Function GetIFontDisp(ByVal font As Font) As Object
        GetIFontDisp = AxHost.GetIFontFromFont(font)
    End Function

End Class

The following C# sample changes the font for the focused item:

axTree1.Items.set_ItemFont( axTree1.Items.FocusItem, IFDH.GetIFontDisp( axTree1.Font ) );
stdole.IFontDisp spFont = axTree1.Items.get_ItemFont(axTree1.Items.FocusItem );
spFont.Name = "Comic Sans MS";
spFont.Bold = true;

where the IFDH class is defined like follows:

internal class IFDH : System.Windows.Forms.AxHost
{
	public IFDH() : base("")
	{
	}

	public static stdole.IFontDisp GetIFontDisp(System.Drawing.Font font)
	{
		return System.Windows.Forms.AxHost.GetIFontFromFont(font) as stdole.IFontDisp;
	}
}
ALL.11:
Your development license key can NOT be used as runtime license key.

This is applicable only to COM object

Make a C++ Win32 application and run the code:

CoInitialize( NULL );
CComPtr<IClassFactory2> spFactory;
CLSID clsid = CLSID_NULL;
CLSIDFromProgID( L"Exontrol.Tree", &clsid );
if ( SUCCEEDED( CoGetClassObject( clsid, CLSCTX_ALL, NULL, IID_IClassFactory2, (LPVOID*)&spFactory ) ) )
{
	CComBSTR strLic;
	spFactory->RequestLicKey( NULL, &strLic );
	USES_CONVERSION;
	MessageBox( NULL, OLE2T( strLic ), NULL, NULL );
}
spFactory = NULL;
CoUninitialize();

This code must be executed only on your development machine, else the code gets you an empty string. The code gets your runtime license key for the exTree component. You can get the control's runtime license key only if you own a developer license key.

This is applicable only to NET Assemblies,  WPF Components

The assembly's runtime license key was sent to you by e-mail once you purchased the component. Please look for "Your runtime license key is "...". Please read the redist.txt file for more information about using your runtime license key.". The development license key and the runtime license key are different. Both keys were generated based on your registration details. The development license key is required on installing the component on your development machine.
ALL.12:
Most of our UI components provides the Appearance object that holds a collection of skins, that's accessible using the VisualAppearance property. These components let the user changes the visual appearance using skins, each one providing an additional visual experience that enhances viewing pleasure. Skins are relatively easy to build and put on any part of the component. Currently, a skin can be defined as an EBN file ( the Exontrol's WYSWYG eXButton Builder saves and loads EBN files ) or a part defined by the Windows XP Theme. A skin can be applied to any part of the control for which we have a property that defines its background color, else a Background property defines the parts where we can apply skins. For instance, the BackColorHeader property changes the visual appearance for the header bar of the eXGrid control, and the Background(exDropDownButtonUp) defines the visual appearance for the drop down button in the eXComboBox control. Each skin in the Appearance collection is identified by an unique identifier from 1 to 126. Shortly, the backcolor properties uses 4 bytes ( DWORD, double WORD, and so on ) to hold a RGB value. More than that, the first byte ( most significant byte in the color ) is used only to specify system color. if the first bit in the byte is 1, the rest of bits indicates the index of the system color being used. So, we use the last 7 bits in the high significant byte of the color to indicates the identifier of the skin being used. So, since the 7 bits can cover 127 values, excluding 0, we have 126 possibilities to store an identifier in that byte. This way, a DWORD expression indicates the background color stored in RRGGBB format and the index of the skin ( ID parameter ) in the last 7 bits in the high significant byte of the color. For instance, the BackColorHeader = RGB(255,0,0) changes the header's background color to red, and the BackColorHeader = &H2000000 specifies that the skin with the identifier 2 is applied in the control's header bar. The &H2000000 is in hexa representation. If the skin is not present in the Appearance collection, a black box is drawn.

The Add method of the Appearance collection defines the type of the skin being added:

  • Changes the header's background color using the current Windows XP Theme ( This option is available for Windows XP systems only, else a black box is displayed )
VisualAppearance.Add(1,"XP:Header 1 1")
BackColorHeader = 16777216

The syntax adds a skin that's identical with part HP_HEADERITEM (1) in the HIS_NORMAL (1) state from the HEADER class in current Windows XP theme. And that means any part that use this skin is identical with the header bars in your Windows XP. Any part from the control may show any part from any class from your Windows XP theme, so you can customize your visual appearance as more as you like. The advantage is that you do not have to define the visual appearance for the part of the control, since you can use any part from your Windows XP Theme. The disadvantage is that this option is available on Windows XP, because it uses Theme APIs, so your application must apply the proper skins based on the Windows is running.

  • Changes the header's background color using a predefined skin file ( EBN files ) ( This option is available for all Windows systems )
VisualAppearance.Add(1,"C:\...\Exontrol\ExButton\Sample\VB\Builder\Predefined\ATX\normal.ebn")
BackColorHeader = 16777216

The syntax loads a skin from an EBN file. The EBN file defines the skins. You can pass the path to the file, as well as BASE64 encoded string. The normal.ebn file defines exactly the way how the part of the control is shown. The WYSWYG eXButton Builder creates, displays, saves and loads EBN files. The advantage is that the skin files are available for any Windows system, from 95 to Vista. The disadvantage is that you have to provide an EBN file, and that means, you have to build one, or to look for on the internet.

Both samples are in Template form. The 16777216 value indicates the &H1000000 in hexa decimal representation, and it indicates the skin with the index 1. Please check the control's help file for the Appearance object where you will find more details about the parts that support skinning.

Also, a skinning tutorial may be found here.

ALL.13:
A newer version of Exontrol.ExImages tool is available here:

Most of our UI components support loading pictures, icons or EBN skin files from BASE64 encoded strings. The Exontrol's ExImages tool loads and compress files to BASE64 strings. For instance, the Images method of the control supports loading a list of icons from the BASE64 encoded strings, Add method of the VisualAppearance object supports loading EBN files from BASE64 encoded strings, or HTMLPicture property supports loading custom-sized pictures from BASE64 encoded strings. So depending on where the BASE64 encoded string is supposed to be used, you need to drag your files to left or middle panel. The left panel is always used to load and compress a list of icons being used by Images method of the control. The middle panel, can be used for any other method or property that supports BASE64 encoded strings.

In case you need programmatically to generate the BASE64 encoded strings from your files ( pictures, icons, EBN objects ), you can do one of the following:
  • Use the Encode64 property, of the eXPrint component, to generate the BASE64 encoded string from a picture or EBN file. For instance, the Debug.Print CreateObject("Exontrol.Print").Encode64("c:\temp\editors.gif") prints the BASE64 encoded string of the editors.gif picture. Use the Encode64Icons property, of the eXPrint component, to encode the list of icons to generate the BASE64 encoded string that cab be used by Images methods only. 
  • pass the path to the picture file as parameter for eximages tool, like: "eximages c:\temp\editors.gif", and so the tool puts the BASE64 encoded string to your clipboard as text. The generated string always starts with "eximages:  ", that should be removed or ignored when calling the Picture method of the control, object or any property that supports BASE64 encoded strings. 

Here's few tips how you can encode your files using the eXImages tool.

  • Drag and drop the file to the left or middle panel of the eXImages tool. Once the tool recognizes the format, it will display its content, and the clipboard is set with the BASE64 encoded string. You will notice the text: "Your clipboard contains the BASE64 format." in the right panel, that informs you that now you can paste the BASE64 format where ever you need it.
  • Open the Windows Explorer, select the file you need to encode and press CTRL + C, or select Copy from its context menu while the eXImages tool is opened. The CTRL + C will display the selected file's content if recognized, and the clipboard is set with the BASE64 encoded string that can be used to paste in your code.

Even if the newer version of the eXImages tool supports viewing EBN files, you can still view and edit EBN files by drag and drop the file to the eXButton's Builder.

So it is important to remember that if you are using the icons in the Images method of the control always drag the icon files to the left panel of the eXImages tool, where a list of icons is displayed. The size of the base64 encoded string is based on the icons you are loading. Even if the tool compresses the icons content when generating the string, it is recommended to load only 16x16 icons. For instance, you can use the MSDEV environment to load an icon file as a resource. Use the Image\Delete Device Image item to remove configurations from the icon's file. For any other type of file, you should drag to the middle panel of the tool.

Initially the eXImages tool looks like follows:

Drag icons to the left panel of the eXImages and you get something like:

The right panel of the eXImages tool generates the following text:

Dim s as String
s = "gBJJgBAIDAAGAAEAAQhYAf8Pf4hh0QihCJo2AEZjQAjEZFEaIEaEEaAIAkcbk0olUrlktl0vmExmUzmk1m03nE5nU7nk9n0/oFBoVDolFo1HpFJpVLplNp1PqFRqVTqlVq1XrFZrVbrldr1fsFhsVjslls1ntFptVrtltt1vuFxuVzul1u13vF5vV7vl9v1BAmBhOCwMKwuDw2ExWJxmIx2HyGLx+SyONyuTy2UzWZzmYz2X0Gbx1kUigUAAMwzGeo1Ws1ZV2Go1IAL+1ACZMxm2+52W63Ov2Op1fC13F0un4nJ1vE2BV2XD2e/4vK4fL63V1bMTKZ5/d2pf3vh6Xj2ff3e63G683S5vF0mmAD4+Xx+bA+wAeP5/H6a/9+h8P2eIAGZAiHHYZkDQQ7TuH/Ap4GUUzjPgiCJn+AD7GBAMNQJBD8wFDwAFlEUExJBaHQdCDixM+UARYABuxg/8ZQ5DUQRpEEbQKf8DxPBDiPe08KRdDEZHVIwANU1YRSWAALSdJsnxpHcFO3HsrOI48Ky1IkKQpERZAA9sjHVC77ynEsqwbBE1RVNKHgAQ04yQ1skvDOJDRkZc9ABJYRT5Jk+z/P0pR49sgQHAsaUVApx0aAD+mvOclSZIkYG7MsMxNTUqyw+FFwVRNQwRSwACFUwADvVNHv9IlNu5V02u5UjzVMIUQxHMYABzXdUVVRpxgBXM60DX9MQHTjWrJE0uzfGkXRdXNa0FYMjxBM8vxJM7iWXN8KSlbs31zWl"
s = s + "T1Ja0eWxM9tNbbkLUhY1mQtaU62hI9hyZUl0x5H6x3ZLVvwtekyWlYlHXNBF0R5dTszdC1vR1cELVJO9JABLODVvMF8x9deGS1fE3yJXYc4pgOKUDfGE31ZN+Srd13U/VdI1y9uCWBPRl2NE1sWxbeWv9l2f6DSNSXdkTaNtd1WyrncR567mgaHGJLanMLY2laVc2FOjW1JpTuX2sV0YhmMtQpXLct1msZRBLmU421exYbN93XgAFixA9s61ztkzbc4u47LHmb6O8ExSPs0j6NOtyv1hSy8BCm6bHs7eUDXMXb5DOLuJyG5v9CjzWLCkszrqZLS2+/NtbwEQdFN9sPbLPEYFU/Fxj1TV2U7WyahslSdM8O9SPGkieK+8iW33fe1JXNUjvqrnWlo1A2lUnieO+/k1lGMs7RjDwvNiciedUtT6Nd3B+RlaxQJBmx8luULWLLPqxjZ769S/UQe1svPUi6M+D5DzN5a2athyHX9H6f43VIjE3yMTbqrlbB5l3OYgU+ssL7X+rtc+2Nj7AD5vwRkkSCyAoFvvg6/FaiZIIuHbGv9DRxEuQeRjC2FkKH/pvRcs4+b+4MFgH+mmISDIhrHN0dqI5uIjRLGYbOJp2YnRRihAaIsQYiRXIdFVKsSImRKiegOKUYIpxZiwg2MsWokxpjFGs7UY4vxvNmWSKwAEHoRjrHRFMZkToMd3HqOcf4lRBN1IKLMg4vGzjnHeRUeY+yNj5GeIkhpJSFkpF+RKKZFoRj9I6Pc"
s = s + "ZJKSElBIGUUR44ljkBJCT0gI1RclZIeN0YZLRalRKqLsq5XRslhIiWUqY0S1l9HCV8YyyEWB8SuYpHiQEiJIAAkpKJmk4QoX8pJFE3zSKCQEA="

Template: "gBJJgBAIDAAGAAEAAQhYAf8Pf4hh0QihCJo2AEZjQAjEZFEaIEaEEaAIAkcbk0olUrlktl0vmExmUzmk1m03nE5nU7nk9n0/oFBoVDolFo1HpFJpVLplNp1PqFRqVTqlVq1XrFZrVbrldr1fsFhsVjslls1ntFptVrtltt1vuFxuVzul1u13vF5vV7vl9v1BAmBhOCwMKwuDw2ExWJxmIx2HyGLx+SyONyuTy2UzWZzmYz2X0Gbx1kUigUAAMwzGeo1Ws1ZV2Go1IAL+1ACZMxm2+52W63Ov2Op1fC13F0un4nJ1vE2BV2XD2e/4vK4fL63V1bMTKZ5/d2pf3vh6Xj2ff3e63G683S5vF0mmAD4+Xx+bA+wAeP5/H6a/9+h8P2eIAGZAiHHYZkDQQ7TuH/Ap4GUUzjPgiCJn+AD7GBAMNQJBD8wFDwAFlEUExJBaHQdCDixM+UARYABuxg/8ZQ5DUQRpEEbQKf8DxPBDiPe08KRdDEZHVIwANU1YRSWAALSdJsnxpHcFO3HsrOI48Ky1IkKQpERZAA9sjHVC77ynEsqwbBE1RVNKHgAQ04yQ1skvDOJDRkZc9ABJYRT5Jk+z/P0pR49sgQHAsaUVApx0aAD+mvOclSZIkYG7MsMxNTUqyw+FFwVRNQwRSwACFUwADvVNHv9IlNu5V02u5UjzVMIUQxHMYABzXdUVVRpxgBXM60DX9MQHTjWrJE0uzfGkXRdXNa0FYMjxBM8vxJM7iWXN8KSlbs31zWlT1Ja0eWxM9tNbbkLUhY1mQtaU62hI9hyZUl0x5H6x3ZLVvwtekyWlYlHXNBF0R5dTszdC1vR1cELVJO9JABLODVvMF8x9deGS1fE3yJXYc4pgOKUDfGE31ZN+Srd13U/VdI1y9uCWBPRl2NE1sWxbeWv9l2f6DSNSXdkTaNtd1WyrncR567mgaHGJLanMLY2laVc2FOjW1JpTuX2sV0YhmMtQpXLct1msZRBLmU421exYbN93XgAFixA9s61ztkzbc4u47LHmb6O8ExSPs0j6NOtyv1hSy8BCm6bHs7eUDXMXb5DOLuJyG5v9CjzWLCkszrqZLS2+/NtbwEQdFN9sPbLPEYFU/Fxj1TV2U7WyahslSdM8O9SPGkieK+8iW33fe1JXNUjvqrnWlo1A2lUnieO+/k1lGMs7RjDwvNiciedUtT6Nd3B+RlaxQJBmx8luULWLLPqxjZ769S/UQe1svPUi6M+D5DzN5a2athyHX9H6f43VIjE3yMTbqrlbB5l3OYgU+ssL7X+rtc+2Nj7AD5vwRkkSCyAoFvvg6/FaiZIIuHbGv9DRxEuQeRjC2FkKH/pvRcs4+b+4MFgH+mmISDIhrHN0dqI5uIjRLGYbOJp2YnRRihAaIsQYiRXIdFVKsSImRKiegOKUYIpxZiwg2MsWokxpjFGs7UY4vxvNmWSKwAEHoRjrHRFMZkToMd3HqOcf4lRBN1IKLMg4vGzjnHeRUeY+yNj5GeIkhpJSFkpF+RKKZFoRj9I6PcZJKSElBIGUUR44ljkBJCT0gI1RclZIeN0YZLRalRKqLsq5XRslhIiWUqY0S1l9HCV8YyyEWB8SuYpHiQEiJIAAkpKJmk4QoX8pJFE3zSKCQEA="
The length of the string is: 1636

The tool displays the number of characters required to hold your list of icons as picture as well. Copy the generated string to your code and pass the s string to the Images method ( or CellPicture property, in case you have generated the encoded string for a picture ) like in the following VB sample:

Dim s As String
s = "gBJJgBAIDAAGAAEAAQhYAf8Pf4hh0QihCJo2AEZjQAjEZFEaIEaEEaAIAkcbk0olUrlktl0vmExmUzmk1m03nE5nU7nk9n0/oFBoVDolFo1HpFJpVLplNp1PqFRqVTqlVq1XrFZrVbrldr1fsFhsVjslls1ntFptVrtltt1vuFxuVzul1u13vF5vV7vl9v1BAmBhOCwMKwuDw2ExWJxmIx2HyGLx+SyONyuTy2UzWZzmYz2X0Gbx1kUigUAAMwzGeo1Ws1ZV2Go1IAL+1ACZMxm2+52W63Ov2Op1fC13F0un4nJ1vE2BV2XD2e/4vK4fL63V1bMTKZ5/d2pf3vh6Xj2ff3e63G683S5vF0mmAD4+Xx+bA+wAeP5/H6a/9+h8P2eIAGZAiHHYZkDQQ7TuH/Ap4GUUzjPgiCJn+AD7GBAMNQJBD8wFDwAFlEUExJBaHQdCDixM+UARYABuxg/8ZQ5DUQRpEEbQKf8DxPBDiPe08KRdDEZHVIwANU1YRSWAALSdJsnxpHcFO3HsrOI48Ky1IkKQpERZAA9sjHVC77ynEsqwbBE1RVNKHgAQ04yQ1skvDOJDRkZc9ABJYRT5Jk+z/P0pR49sgQHAsaUVApx0aAD+mvOclSZIkYG7MsMxNTUqyw+FFwVRNQwRSwACFUwADvVNHv9IlNu5V02u5UjzVMIUQxHMYABzXdUVVRpxgBXM60DX9MQHTjWrJE0uzfGkXRdXNa0FYMjxBM8vxJM7iWXN8KSlbs31zWl"
s = s + "T1Ja0eWxM9tNbbkLUhY1mQtaU62hI9hyZUl0x5H6x3ZLVvwtekyWlYlHXNBF0R5dTszdC1vR1cELVJO9JABLODVvMF8x9deGS1fE3yJXYc4pgOKUDfGE31ZN+Srd13U/VdI1y9uCWBPRl2NE1sWxbeWv9l2f6DSNSXdkTaNtd1WyrncR567mgaHGJLanMLY2laVc2FOjW1JpTuX2sV0YhmMtQpXLct1msZRBLmU421exYbN93XgAFixA9s61ztkzbc4u47LHmb6O8ExSPs0j6NOtyv1hSy8BCm6bHs7eUDXMXb5DOLuJyG5v9CjzWLCkszrqZLS2+/NtbwEQdFN9sPbLPEYFU/Fxj1TV2U7WyahslSdM8O9SPGkieK+8iW33fe1JXNUjvqrnWlo1A2lUnieO+/k1lGMs7RjDwvNiciedUtT6Nd3B+RlaxQJBmx8luULWLLPqxjZ769S/UQe1svPUi6M+D5DzN5a2athyHX9H6f43VIjE3yMTbqrlbB5l3OYgU+ssL7X+rtc+2Nj7AD5vwRkkSCyAoFvvg6/FaiZIIuHbGv9DRxEuQeRjC2FkKH/pvRcs4+b+4MFgH+mmISDIhrHN0dqI5uIjRLGYbOJp2YnRRihAaIsQYiRXIdFVKsSImRKiegOKUYIpxZiwg2MsWokxpjFGs7UY4vxvNmWSKwAEHoRjrHRFMZkToMd3HqOcf4lRBN1IKLMg4vGzjnHeRUeY+yNj5GeIkhpJSFkpF+RKKZFoRj9I6Pc"
s = s + "ZJKSElBIGUUR44ljkBJCT0gI1RclZIeN0YZLRalRKqLsq5XRslhIiWUqY0S1l9HCV8YyyEWB8SuYpHiQEiJIAAkpKJmk4QoX8pJFE3zSKCQEA="
With ExplorerTree1
    .Images s
    .Groups.Add("Group 1").Image = 1
    .Groups.Add("Group 2").Image = 2
    .Groups.Add("Group 3").Image = 3
End With

Run the form and you get:

Alternative, you can use the control's Template page to add the icons at design time, by generating the encoded string for icons one by one like in the following sample:

BeginUpdate
Images("gBJJgBAIDAAGAAEAAQhYAf8Pf4hh0QihCJo2AEZjQAjEZFEaIEaEEaAIAkcbk0olUrlktl0vmExmUzmk1m03nE5nU7nk9n0/oFBoVDolFo1HpFJpVLplNp1PqFRqVTqlVq1XrFZrVbrldr1fsFhsVjslls1ntFptVrtltt1vuFxuVzul1u13vF5vV7vl9v1BAmBhOCwMKwuDw2ExWJxmIx2HyGLx+SyONyuTy2UzWZzmYz2X0Gbx1kUigUAAMwzGeo1Ws1ZV2Go1IAL+1ACZMxm2+52W63Ov2Op1fC13F0un4nJ1vE2BV2XD2e/4vK4fL63V1bMTKZ5/d2pf3vh6Xj2ff3e63G683S5vF0mmAD4+Xx+bA+wAeP5/H6a/9+h8P2eIAGZAiHHYZkDQQ7TuH/Ap4GUUzjPgiCJn+AD7GBAMNQJBD8wFDwAFlEUExJBaHQdCDixM+UARYABuxg/8ZQ5DUQRpEEbQKf8DxPBDiPe08KRdDEZHVIwANU1YRSWAALSdJsnxpHcFO3HsrOI48Ky1IkKQpERZAA9sjHVC77ynEsqwbBE1RVNKHgAQ04yQ1skvDOJDRkZc9ABJYRT5Jk+z/P0pR49sgQHAsaUVApx0aAD+mvOclSZIkYG7MsMxNTUqyw+FFwVRNQwRSwACFUwADvVNHv9IlNu5V02u5UjzVMIUQxHMYABzXdUVVRpxgBXM60DX9MQHTjWrJE0uzfGkXRdXNa0FYMjxBM8vxJM7iWXN8KSlbs31zWlT1Ja0eWxM9tNbbkLUhY1mQtaU62hI9hyZUl0x5H6x3ZLVvwtekyWlYlHXNBF0R5dTszdC1vR1cELVJO9JABLODVvMF8x9deGS1fE3yJXYc4pgOKUDfGE31ZN+Srd13U/VdI1y9uCWBPRl2NE1sWxbeWv9l2f6DSNSXdkTaNtd1WyrncR567mgaHGJLanMLY2laVc2FOjW1JpTuX2sV0YhmMtQpXLct1msZRBLmU421exYbN93XgAFixA9s61ztkzbc4u47LHmb6O8ExSPs0j6NOtyv1hSy8BCm6bHs7eUDXMXb5DOLuJyG5v9CjzWLCkszrqZLS2+/NtbwEQdFN9sPbLPEYFU/Fxj1TV2U7WyahslSdM8O9SPGkieK+8iW33fe1JXNUjvqrnWlo1A2lUnieO+/k1lGMs7RjDwvNiciedUtT6Nd3B+RlaxQJBmx8luULWLLPqxjZ769S/UQe1svPUi6M+D5DzN5a2athyHX9H6f43VIjE3yMTbqrlbB5l3OYgU+ssL7X+rtc+2Nj7AD5vwRkkSCyAoFvvg6/FaiZIIuHbGv9DRxEuQeRjC2FkKH/pvRcs4+b+4MFgH+mmISDIhrHN0dqI5uIjRLGYbOJp2YnRRihAaIsQYiRXIdFVKsSImRKiegOKUYIpxZiwg2MsWokxpjFGs7UY4vxvNmWSKwAEHoRjrHRFMZkToMd3HqOcf4lRBN1IKLMg4vGzjnHeRUeY+yNj5GeIkhpJSFkpF+RKKZFoRj9I6PcZJKSElBIGUUR44ljkBJCT0gI1RclZIeN0YZLRalRKqLsq5XRslhIiWUqY0S1l9HCV8YyyEWB8SuYpHiQEiJIAAkpKJmk4QoX8pJFE3zSKCQEA=")
Groups
{
	"Group 1"
	{
		Image = 1
	}
	"Group 2"
	{
		Image = 2
	}
	"Group 3"
	{
		Image = 3
	}
}
EndUpdate

Just copy and paste the code to the the ExplorerTree's Template page.

Now, let's try to change the visual aspect of the group's header by using an EBN file:

The right panel of the eXImages tool generates the following text:

Dim s as String
s = "gBFLBCJwBAEHhEJAEGg4BO4Rg6AADACAxRDAMgBQKAAzQFAYahgGqGAAGEZBRgmFgAQhFcZQSKUOQTDKMIziYBYJhEMQyDYAUIjHCEOBqGaQBxASQpUhqHYDTbIMByBIUIxNFCQBhlKBIHhyPIbUbGQKQSBMPwTIYAH7qKoaThaPw2UDUkx5ADKUIiSAiMZpVRlHQHKCptqWVS0XBLCIZBpteCYOrODQwXZNEgUXDVRQHJqNLQqOyYXpeUIsxbrIZ5EjXDgATjOMgUTgsSwTE6sMrrKhZYxSFqUCrCN6AALlTABQS1MItWhMZgTC5dV7SEI3cAGQwHMiBdJnOj4JwTKqWThcWI3TasI6LRy9YR2YANUzqF6oWrlOqYOKuNxQBuDBzloaI2AAAYjmWRY6BueAeBoV5VkuDZ6nQLhGk6S43mURp8FUXgGEOBRumMXg/BeHwOhsR5dG0HgGD2bBAkCBAkFAGhGDGUB1ByBhXGUCQ9gaRAMEIExhAQaA2EIQoECWOBpBSYBhBcMAhBgCQWFoYhIhYJoJmKCImCqCpikiNguguYwIkYMoMmMSJWDaDZjgiZg6g6Y5InYPhAmKE4InMPpOAORJ5DgDwDmCXg7g8aQuE2EwkmkIJ4hEZB5BiYQ8g+KQInuFojmkdhehe6IGGKGJmEmFhmg8ZAIhYVw+iSYxsmsPJNHOHJuDSTgzi4dIdicWZeHcNYOGONhxDuJ5zGCaQ8CgI5CG4PJoHkOoKhQJJJEoVIjmQah"
s = s + "CFUPhmHoVoWiWaYKGaGommMOYkn+FokmoFh3DKTYjgSRA0g2EwElANYMAMPJVisTRaiiVop0iGJUDaTBzFiXQyA0cx4koNhOAqEJhDODZThKRA5A0A4AmcNBOCOJh6h0Z5JnocofmyeZilaMhOHoFoJiNRxSGuGplkocpijibhLhaZoYGmaRSgeHZrhMdI7DITJykCPQwkqMpgj4KgLFKbIlCyC4LmCO49EuYo0joMAvCMDIzDADBsByRgtgwMwkjgMYMkuPJPC+DJDEsFA0isCpKjSLYNjMGJVDcK5DHsIZImuWweliMwsmsQh9jQaAaA6BQ2g6I5KgcNwOkOUoLhObZZCaEo3mWC4GmeT50A0BxCg2LoZBof4wjEK54hkKQKiINIYCcSICEi+5JHILIVCaNJiHSEQmkoDRsiAJQJnKFIXCiCh9CyKnunKNIeCqCwCgSLQsm+MpjHGP+6gsBI8nCFgKwGRDhiAwJYF8AADAZFEGwMYdRfBDC+NgGoKRNBuA4FkGolRJjZFmN4K4Phyi0BKAcTAZgph+DSJsLYkhHB1CQMobI7BDifDQH0F4TRpjHAuEwSYaBxiYBcMwIQkRyCgHQD8CAQwoDmB2PYboxw3A4AeCMd4eRvh3F6JkAo4QHhEAyA4H4kByBnEgEYCAZAwgjGwBITQphUirDWBoPwvRYBsC2CYZotAKi7DiGYKT8RbDnD4OADYrgDiCHeFgNw9xDjiBuIYf4VwrBcAuAkKgYxsgFD2MQLA"
s = s + "XAvgbDEPIDITRWC0CyGIOQUBVhpBuK0WwcBmjUDmKAD4KxAjRFIDcKIAxwCCEqFMZIOQdi/BMAAa4ngUCHAYOEXAOQCiAF4BgIQkAsALDgHgGAwgkBIAuANvYhQICqAoIYCA0gNghDoDAQo8A2A5CGEcOYDRujbF6Hcd4CRxA8DOJYeQ3g1jPDtDcVYtRLiuGwF4YY2w2gtlcLYe4wB8CXHGHQLwzRsi7B9OQfQ2BBjsDeMwKojBVC3HIMYbA+xDzVASGMXA5RLDkCmMsFQWglACACDIcoBhQjgBoAgOY6gmhvB0CEe4BAxjEDyIINIMRKAKCCIoG4xBcCxAwK0Mo3xhC4CEBYYQKAmAKACAgEgBBUgSAoCQPgkRIhBBQCgQoSQUglFIKwS4kB5BuAiEgPATQDjhB4CkQocDfhDBwDkBonRdi5DuPIVo4BdhIBmAYMI+xkiIBeEIEQPQrC0GuB4YgSQ0iPDkCYHo6BPD4GuPwKYfB1jOBWDAWwGwLCXEIFsMYDxghVFwFUOArhRgQHAH8KIlR/AsFMFAcghw2ABA6NABoyxZgWDMM0LIuxPBKDgCkJIRwoj0GeCcHQWBOgTFcHUJw2Rpg7HOGQeAnRpjGD0E8HI7QeCnGIPUT4MRtAJAsLQUgLxDDAHWAYQQXA+ADGiDQHoAR8CWA6EEDASAGhgDcCEQwmAbgOEELoRIChwMmAIK0C4EojAwAQEAPwFxBjdA+A8MA9AVAGEUEgDQJBKCLEiLIGAJQpD"
s = s + "KCyEoNITBLimCkFYJwBRdBrBOOEFgHxCh0HdVwfAYwGgqAIBwQ4ARvBWAONgPIKxPA0FgHkGIARzhLCMKQeoIgaC4ESA0QwJQbCmGyC8T4DBgB8GaN0QYMBDjSG+B8NYEwxCvF4GoYo9x0CtGuGsEIfwXAyBmDIRIrwNCgAGJQLRkwbBXCoP8Lo6xSh4FcNUcwvgri6H6F4VgBQ+iwBqP4YIWAtDrBuBQGQbwlApAyNIEwiR+CREMFAcAHRwgMCeI8PQBgfAsiyKASwahmXVB6GcNgwBKAeCANQIwDgVhIBwKgPoERRAAG4D8BgOwshrFQJ0CoowqByEeFIBQTwkjpDqCsW4VBbDdGkPkCoIx0icEwLgKQagnDcC0G0BAqRiChEKIETQUhhggGyFAMIrQhCVBgOUcAVAzhpi6D0JQeceimGIDYUoVAtDtCkHsFolgujEF0K4bY6hpD2FWHMCovRiiKGGFkDgCxBhWEmDkRwXwqhvD6Jgdo9xfhXHMP4L4ix+h+HeP0fowAMAPACGALgAxAjwBKPURgKh6nNEKKMAIrA1A5DQKMcwyBHDwcOMcZANwJgWC0M8bIzAeiHDiAUUAwx8CLAgNkTYRAGgxB6KIAwogiB1C0HsKYa9FiyFGBQNQkQth6CWI0VIRRfiRCsOYI4YxUghEeK4AgmRkBXAUJoaYeQgiRGGA0HligbDoCoDoRYDh3C9r0PUFw7giAnFGFMcQKxrBrEiBwKQ1Qsh7AmKoZgUQvgxCSI"
s = s + "AWAOBUiZFmEAYAzB8irBoOYXg3RNhzEMGwZwWRfg5HOBwdInR5i2DyM4KYFR7AVgDgIBOhqAdAqAjhyhWgahGgIhlAeAhBYBUBhhMBJgjAxAegOhEg6BDBGhpAdAfrQAuAog0B4gzAXBag7BbgMAogdAag2B0B2haBjBcBvBJBkB+A8hUh2hugYBJA8gHBwByAthGgnAZAqBRhThtBnBzhlA9hSB3BVASAdBrgrgsAgglB8A+hKgPAyhuhlB2gqhVhqgDBPg8ANB7Bkhlg9gXB4B2BuhKhZhbAzBnhtAtgjg1A2gGhWhaB7BfBqhtgNgwhYhFA8BMBgAPgxB2hoAEhegVAwgKAyBThJBpBCgGgBBcA7h0gmhuhSB7nDBvJhg8g3guh0hDhYgrBMhaBdA1BqgogOgcg2A6B7AZvNhPBIgpBNg+glBWhzgEhqgsB+AUAuAOgtg4hag6ARhkgNBjBPBuB1hQgVAahiBVBrg8gfhGh4hthVhjgcB/gPByAOBHhIg5AvAhhkh8gTgUBrg4AzAQBarTBvBsBxBsAnh3AxNwhqBJBNBoglBPAWgVAOAegFgYhnheh7hPgghvBugFhQA6AfBGhog9AjBJhigbBHBpBxB+h/gigcAGgMvNhFgohpA2gkhqhYhngEBjhOAXgQBuAeBDhiA5Aagch2ArgTgSA7AnBjhsg9gjgzh2guhNhbA7BPBthtB9g7g4hkn3huBghPAuB8AsApBYA/BYhJA1BHMoBQg2AsB8gz"
s = s + "huB0BUgUA4gIAXyegkgPgABiAlBHhAAtASB+A7hIB4h/AjhlRqgWhyBeBjhKh5gfAvhmorP6B+BvhQh5hvBFhoA9Afgmh0g+gjs1AvBPhpAEgGgYAdBYg/BNhahugfgMg6gVAbgjg9BWgThqBrB7hvA4BWBAh3h8FgB8APgFhwB+RrB4g/AjhiB8gvgPBMByAcArgGgQBlgshEhFh8hBBvB3F0BrAdBog5g9AEBVBRGdASAjAMB3B4grAoA9hwg4h5h8hfzrB+gfhPh6g/Bvhsh9h/gvh4h+hvhlh8A/gfh2h+g/hjh6T1hvyMhPh8B/usgAAXh9gAA4AAB+gwBMAJhQhsgABwhsBQgQhqgAglAMANBoAPAEkaALgYASALgQBQAHgwgjAEBgBxAJgoAagBhIAbgBhYAggBh4AigBhoAkgCAYAlgCA4AmgCgYAogCg4AngChYAqgChoAsgCh4Ay0cAXPOAiBCBEA0A8AkBBA1gUg6AKgjheAwADB7A/AihYAoBSBSAagnheAkhAglAMgwhqBvBHgMS0A1AJgAh4AKgAhVAPgwhtAPggh9AOBgh2gFB4BZgFgIBagFhYBcgFh4BbgGAYBegGAoBggGJYAGBYBogGBIBqgGB4BrzKhsgGh4BugHAYBtgHA4BwgHBIBygHBYB4gHB4B6gHBoB8gHgYB9gHg4B+iKgAgGloAPgAh9AMhAhoAPhABsAItZhIh0AkBTh0AcBlAAgCA8gzBUA9gDBxA+hDAhS3B"
s = s + "OgES1AkhggqAMhwhvBhgmgLBiA4BNgEh4BRgFA4U7BYgFgKgogGgKg4gugKhYgwgKhIgygKh4gzgLAYg0gLB4g2gLgYg1gLg4g4gLhIg6gLhYhAgLh4hCgLhohEgMAYhFgMA4hGgMgYhIgMg4hHgMhYhKgMhohMgMh4hSgNAYhMANAghsAPhYA1BwB3BhgJAAByA8AjBUBEhDAKSqAaAkhIgcUmhSALBwhWAOhXhkBpBIglgFAIBSAPg4hTgNAIhygPAYh0gNBIhzgPBoh1gPB4h6gPgYh8gPgIh+2rh/gPhZAAgPgohWWagdVMg9BwhVA0BCAkAxA7hzhQWgh7AyASB/gJg3hdAiBSBUBQAAhrgOg2gRgOhYgngPAJABgRh5ADgQApAigSAJAjgSAZAkgSBw0+BAh2APhghlAPBwh/AOBigUU+h4APh5AtXbglgTB5AolABNANBwhugQBlQzBWggAIBG3GAABVAGhAgAA8Aj2gBzASAsB4BEAkBohlAWgSBUBhBWgJgKA2AhgRhIhvgTgpBYgTgZBagSBpBcgVgZBdgVg5BegWAZBggSgJAFgVA3gTBohmh5BihWAsgAhIAKAKBQg+ANADAcAnByBOB4AxBrXuBrAtAZBTgOhHgNgKBpBXgWA5BfgX4BEsB+gYAZgEgYJ4gYApADgWBWgKl8BEBQBAB0YEhRAxByhYBoAZBOAiBXgEAphyBDBugms6goBOrmhTgYBZgIgaAJgigYB5gjgaAZgkgaB5"
s = s + "gmgMhZgKAPB5gMB0BgBgAJhwhaA+hDh6gUhSgUAigJgXL1yEg2htgRg5B7gZhpAegagZglgcAZgogcAphAgcA5hGgcBZgJgNB5BmB5AGh0gWhZBvgJgSB9gRBCAqgbBxBSA5g3gHB4gZg8gZhZAdgcBJhcgcB5hdgcgJhfgeAZhegPh5grgaj2AKAggTALAwhOA/ApByAkhHA4Aig5hUAPhyBOgdB5gcgXhJgfgeA5hggfkwAfgZh8gfg5h+gPBphlgchGgRgYh5gRAxBZgTBuBJgVAihZhxAkhoBJgEg5hZgfBpz5B5h9gfgqAUghA6AWghAphfggAWgVgah5gxAxACkmhCBJBuB5B1gJhSBM4yBvADhAgbBpBZBWgfB6LLhaAYgihqAwgihaAygaAKAaBZhIAMgWhpBwAxh4hjAPBmhmgfAKAjgOBiBGgOgAhtBQBgh0gKBJg9gdg6Axgih6Az4rhMgkg6BOgPgaA1BQBIgiAINZgMhCgwAygDgbgehygdgjh5BQBZAFgSgR4tAixjgkhaBKgmBaBkgmB6BPgfgKAagKBqAcA3yGgoA3hcA0BKBcAVAiBrAnh6BgBZhKBigmBqBpgng6B6gnkCAYAaAagAhzBxgZAihKgdAjgpgnA5gYAPgygFgXgZBVgkB5B9gnhKB/gpAagQgpA6B+gagZAFAGAAgugEhmAsA1pi0uhRgEBSA6gfaUAoA5oXBpmFh6gVgqgagSgqgqgUgqg4gxgaiig1hjB2Axh"
s = s + "CB/gnAagHAihAhaAOhAh1BzhXLhBagn7KgsgsAagugqhahEgpBZA8WagVA7h6gyAwA6g0AnAqBagrByArmYAIgqBqAQgsAqhFgsA6hWgtgaAVgIgIgKgIhKhKA1hKgzb+h/gshyA3gfARBpB9h3hhgtBJg+gtgqhXguhahsguh5gogthIgLHFhfAKDhgNg6hjUbg7guBhBSgghIBKgugqBIguySgwA7ACgwazgvAqlGBahLV9higshqh6gqAagIguByBMgkArAAn4AEgvALAGgxB7AagagbAIgvBLAKguAKhMgwhQhuguBKByAihEh/BQaNgngKgOgsALAbgxgLAugyhbAwgMhbAdgvBah3gvgQh6gvg7ARa+hUAMBAhcgOglgVgygqg/gmA7AZg0A7Avg0BLAxgPgbAzgxh6h2gyAah4gwhrA3gxALAmglhghvgohFgggnkVg1B7BGg1gbWOBrBJAHhbALgshbAjgwh2ASgzgQh/BoBWgHAFwrBQAlgfg1BrBag1gLBbg2hrBYg1hbBfgyArAkAjBah8gogZgagbg7BVgyg7BCg2h7Btg3h7B+gpBbBygyALAMg0hbBhg0h7BjAih6g5grg3A+g0AKhVg3ALgAg5JugwBLAdXohYAwBShtgzBrZgB3gGgtA7Brg3hLgTg5Ab6yAbAHgIgQB6AJgwg4BBgTBmAwgjgIAoBbB1AjBLB3AWgbgLB+AHhig5h7BBg6BLgSg7zQgmgKhcg6BwiihDhegbAj"
s = s + "gMA5gKA9glgyAvgvhqAOg3g7+vgrg4g7g7hOgfg6hcglBAhMA2bqArUvA5g7hFgiArhHgiBYgggkBFgXg2hLhNg+AbhMg+A7AcgIgQgUALgwhcAwBTAXA/gpATgOBFgOAih4hngOgaGvgLhkg+ArhPg/BZgHgtnvTbh6B9gjA1grBrBQAihrA7gzhYAKg9h7OAAQ0LBwh95BALhAgsVgh8AOhBAcANhBA8AQhBBMAShBBcAYhBB8AahBG7hBgcAdhBg8AehCAcAghCA8AfhCBcAihCBsAkhCB8AqhCgcAshCgMAuhCg8AvhChcAwhDA8AyhBg4gpgQDn4Hh/B9mCBAhAGu3iK1mY0QaFUAyyAEmClg+NVwGFCyg+mEqiUwl0SuFCiXwpUS2FSihwq0UeFaixwsUWeFei1wtUW2FyimCkA5I0YeGCjHwv0aOGGjTw0UamGqjVw4Ua+HKjWw6UcOHWjjw7UeOF+jGCZA2QXuHXSxUABF2dhEpCWRxiakWOSKAXikSyGSKOQ2kTyHUkORCkjyH0kuRKkmyKUk+RqkxyOUmGR6kzyP0muRI/EezRUclOUwC8AawTUHwA8gugXkESCig+QR0GWC8w64TcG0C90s+TmlwydUuuTyl3yd0wOT6mCygUweaQuUimEylUw+UumRymUy+U6mhym00eVCmkypUymH0HzquCmGQQREONyotT6CVyxHiuWM8TyyU4+TNJ0OTLJ0eTRJ0mTVJ0uThJ0+TlJ02TpJ0GQVJ"
s = s + "QjAxCoeRVJUmRdJYAT1IgwTyBQYSiB8OSyBcoTBJsUQSbc4gfKg8yhLoHCCBkuwuME3geLkWgfC8FSiPMGjoO0IwUFkHj8JkTxTDk9w6PcaATGEhgcLQGgWCEmgckEpR6FkpS3LQRgkKknzaDEoxaGmSzwigTDRFkUSfHoKygBkZooHREzEB8FSPKEWgZKU2iRKkOiVHEJBpKc7wVGULQjKY+RRDcWgrDo+T9Kc+RtJcGiEB8EgLKg2iXKs+jBKwJDHKIJBLB0+g5JQawqPw2h3JWeZrAUqAZHEoDIO8rBaOkri6OwaBaMgRCVI8oC6A8jDELQHBBOkqD6O8sB7AksCnE8rw7A0sQ7BUsR6BoIBiAJAQ=="

Template: "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"

The length of the string is: 8000.

Your clipboard contains the BASE64 format.
So we can change the control's template as follows:
BeginUpdate
Images("gBJJgBAIDAAGAAEAAQhYAf8Pf4hh0QihCJo2AEZjQAjEZFEaIEaEEaAIAkcbk0olUrlktl0vmExmUzmk1m03nE5nU7nk9n0/oFBoVDolFo1HpFJpVLplNp1PqFRqVTqlVq1XrFZrVbrldr1fsFhsVjslls1ntFptVrtltt1vuFxuVzul1u13vF5vV7vl9v1BAmBhOCwMKwuDw2ExWJxmIx2HyGLx+SyONyuTy2UzWZzmYz2X0Gbx1kUigUAAMwzGeo1Ws1ZV2Go1IAL+1ACZMxm2+52W63Ov2Op1fC13F0un4nJ1vE2BV2XD2e/4vK4fL63V1bMTKZ5/d2pf3vh6Xj2ff3e63G683S5vF0mmAD4+Xx+bA+wAeP5/H6a/9+h8P2eIAGZAiHHYZkDQQ7TuH/Ap4GUUzjPgiCJn+AD7GBAMNQJBD8wFDwAFlEUExJBaHQdCDixM+UARYABuxg/8ZQ5DUQRpEEbQKf8DxPBDiPe08KRdDEZHVIwANU1YRSWAALSdJsnxpHcFO3HsrOI48Ky1IkKQpERZAA9sjHVC77ynEsqwbBE1RVNKHgAQ04yQ1skvDOJDRkZc9ABJYRT5Jk+z/P0pR49sgQHAsaUVApx0aAD+mvOclSZIkYG7MsMxNTUqyw+FFwVRNQwRSwACFUwADvVNHv9IlNu5V02u5UjzVMIUQxHMYABzXdUVVRpxgBXM60DX9MQHTjWrJE0uzfGkXRdXNa0FYMjxBM8vxJM7iWXN8KSlbs31zWlT1Ja0eWxM9tNbbkLUhY1mQtaU62hI9hyZUl0x5H6x3ZLVvwtekyWlYlHXNBF0R5dTszdC1vR1cELVJO9JABLODVvMF8x9deGS1fE3yJXYc4pgOKUDfGE31ZN+Srd13U/VdI1y9uCWBPRl2NE1sWxbeWv9l2f6DSNSXdkTaNtd1WyrncR567mgaHGJLanMLY2laVc2FOjW1JpTuX2sV0YhmMtQpXLct1msZRBLmU421exYbN93XgAFixA9s61ztkzbc4u47LHmb6O8ExSPs0j6NOtyv1hSy8BCm6bHs7eUDXMXb5DOLuJyG5v9CjzWLCkszrqZLS2+/NtbwEQdFN9sPbLPEYFU/Fxj1TV2U7WyahslSdM8O9SPGkieK+8iW33fe1JXNUjvqrnWlo1A2lUnieO+/k1lGMs7RjDwvNiciedUtT6Nd3B+RlaxQJBmx8luULWLLPqxjZ769S/UQe1svPUi6M+D5DzN5a2athyHX9H6f43VIjE3yMTbqrlbB5l3OYgU+ssL7X+rtc+2Nj7AD5vwRkkSCyAoFvvg6/FaiZIIuHbGv9DRxEuQeRjC2FkKH/pvRcs4+b+4MFgH+mmISDIhrHN0dqI5uIjRLGYbOJp2YnRRihAaIsQYiRXIdFVKsSImRKiegOKUYIpxZiwg2MsWokxpjFGs7UY4vxvNmWSKwAEHoRjrHRFMZkToMd3HqOcf4lRBN1IKLMg4vGzjnHeRUeY+yNj5GeIkhpJSFkpF+RKKZFoRj9I6PcZJKSElBIGUUR44ljkBJCT0gI1RclZIeN0YZLRalRKqLsq5XRslhIiWUqY0S1l9HCV8YyyEWB8SuYpHiQEiJIAAkpKJmk4QoX8pJFE3zSKCQEA=")

VisualAppearance
{
	Add(1,"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")
	Add(2, "CP:1 0 0 -20 0")
}

BackColorGroup = 33554432
GroupHeight = 48

Groups
{
	"Group 1"
	{
		Image = 1
		Alignment = 0
		IndentHeaderLeft = 12
		IndentHeaderTop = -8
	}
	"Group 2"
	{
		Image = 2
		Alignment = 0
		IndentHeaderLeft = 12
		IndentHeaderTop = -8
	}
	"Group 3"
	{
		Image = 3
		Alignment = 0
		IndentHeaderLeft = 12
		IndentHeaderTop = -8
	}
}
EndUpdate
and we get the result:
ALL.14:
Our encoding includes compressing the stream (file), so any stream you may need to encode, first is compressed, and after that the BASE64 encoded string is generated. 

In conclusion, you must use the following type of encoding, instead using any standard encoding.

  • (design) Open the eXImages tool, and drag and drop the file you need to encode.
  • (code) Use the Encode64 / Encode64Icons property, of the eXPrint component, to generate the BASE64 encoded string from a picture or EBN/icon.
  • (code) Pass the path to the picture file to eXImages tool, and the tool copies the generated string to your clipboard, with the prefix: eximages:
ALL.15:
The Exontrol's ExImages tool can view the original icons, pictures or EBN files from BASE64 encodes strings. Once the clipboard changes the eXImages tool try to locate a known file, and if found it displays its content. 

Here's how you can see what a BASE64 encoded string contains:

  • Select the text where the BASE64 encoded string is, and press the CTRL + C, in any application. If the eXImages tool can found a known type it will display its content.
  • Select the text and paste in the right panel of the eXImages tool.

Let's say you you need to get some EBN object from the gallery section.

  • Run the eXImages tool.
  • Click the gallery link, and click a picture where you want to take EBN elements, so a TXT file will be displayed in your browser, or directly.
  • Select the line or lines that contains the BASE64 encoded string
  • Press the CTRL + C, and the eXImages tool displays the content that has been found in the selected string.
Even if the eXImages tool is able to view EBN content, you can still use the Exontrol's eXButton component that provides the WYSWYG EBN builder, that helps to view and edit EBN files like explained here.
ALL.16:
The most frequently error is that the ICO files was not dropped to IconsList panel of the eXImages tool. The eXImages tool displays two panels that accepts and displays pictures. The leftmost panel displays a list of icons ( so each ICO file dropped is appended to the IconsList panel, in other words may display several ICO files ), that can be used on Images method, since the next panel displays a picture file one at the time, usually for properties as HTMLPicture, CellPicture, Picture, and so on. The first panel generates base 64 encoded strings for a list of ICO files, since the second panel generates the base 64 string for a single picture. 

In conclusion, 

  • Icons - If you require to fill the Images method ( a list of icons ) of the control always drag your ICO files to the leftmost panel in the eXImages tool. In this case the Image property ( not Image(s) ! ) specifies the index of the icon being displayed in the object. Once you drag files to the leftmost panel, the generated string always starts with: "gBJJ...", in other words the Images method require a base64 encoded string that always starts with "gBJJ...".
  • Picture - If you required encoding a single picture file for properties as HTMLPicture, CellPicture, Picture and so on, drag the file to the second panel ( "Drag here a file such of .bmp, .gif... )". If the dropped file is a picture, that panels shows it, and the encoded string is shown in the rightmost panel. The eXImages tool is able to encode any type of file, no matter if it is a picture or not, so always the right panel displays the encoded string. For instance, the Skin parameter of the Appearance.Add method may take an encoded base64 string for an EBN file, and this string is still generated by eXImages tool.
The eXImages tool compress, encrypts and encodes the dropped files.
ALL.17:
First, you need to install the Exontrol's eXButton component that provides the WYSWYG EBN builder. Once the eXButton/COM is installed run the Builder shortcut in the installed folder.
  • If you have ran the builder for the first time, you might need to reposition the opened windows at your choice
  • Open a notepad editor when you need to paste the Template code, or the BASE64 encoded string you want to recover to a file
  • In notepad select the BASE64 encoded string ( usually it starts with  gBFLBCJ... ) without including the quote characters, and Copy it in the clipboard ( CTRL + C )
  • Go to eXButton's Builder tool and press the button load 64 . If you hover the cursor over the Load 64 Button its tooltip says: "Load from the clipboard a ..."
  • If the BASE64 encoded string is recognized the Builder tool shows the original EBN file.
You can do changes to the EBN file and save back to the clipboard by clicking the button save 64.
ALL.18:
Yes. You have to define the picture file with a transparent color. Use an image processor ( such of Microsoft Image Composer ) to save your pictures using transparent colors. For instance, the GIF, PNG formats accept transparent colors.
ALL.19:
What are Memory Leaks?
"When a program needs to store some temporary information during execution, it can dynamically request a chunk of memory from the system. However, the system has a fixed amount of total memory available. If one application uses up all of the system?s free memory, then other applications will not be able to obtain the memory that they require. The implications of a ?memory starved? application can range from a graceful shutdown to an unexpected crash. Most large scale applications regularly request memory, so running out of system memory tends to have a domino effect. Even if the applications do not terminate, the system will slow down to a crawl?or even hang?in low memory conditions. Clearly, none of these results are desirable, so the system never wants to run out?or run low?of memory.

It is the responsibility of each application to ?free? dynamically requested memory when they are finished using it. Freeing the memory returns it to the system, where it can be re?allocated to another application when needed. When an application dynamically allocates memory, and does not free that memory when it is finished using it, that program has a memory leak. The memory is not being used by the application anymore, but it cannot be used by the system or any other program either.

Memory leaks add up over time, and if they are not cleaned up, the system eventually runs out of memory. Most everyone has seen the ?Your computer is running low of virtual memory? message box on Windows when memory gets too high. It is typically accompanied by horribly slow response time, and often the user can?t even close the wasteful application because of this sluggishness. The only response at that point is to reboot the computer"

Quote from https://msdn.microsoft.com/en-us/library/ms859408.aspx

We created a a Stress application ( built on C++, starting from VS 2010 ), that adds and removes contiguously items (bars), to check for memory leaks. The Stress application you can download bellow, includes the source code as well.

You can:

  • download here the Stress application for eXG2antt component
  • download here the Stress application for eXGantt component
  • download here the Stress application for eXGrid component
  • download here the Stress application for eXTree component
  • download here the Stress application for eXList component

You can locate and run the Stress.exe under the Run folder, such as: "..\Stress.ExG2antt\Run\Stress.exe" 

The following screen shot shows the memory usage of the Stress application for eXG2antt component, after running the Stress.exe for 100,000 times, to load and unload 100,000 bars:

The following screen shot shows the memory usage of running an application, WITHOUT memory leaks, for a specified period of time:

( As you can see the memory usage stay constant while running the process. )

The following screen shot shows the memory usage of running an application, WITH memory leaks, for a specified period of time:

( As you can see the memory usage is growing contiguously that clearly indicates a memory leak )

We have used the Process Explorer tool from sysinternals to show these graphs.
ALL.20:
Most of our UI components provides a ReplaceIcon method that can be used to
  • add a new icon giving its handle
  • remove an image
  • clear the images collection

The Images method can be used to attach a image list to the control. 

For instance, the following sample adds 2 icons using the LoadPicture property of VB which uses the LoadImage API function:

Private Sub Form_Load()
    With ExplorerBar1
         .ReplaceIcon (LoadPicture("E:\Temp\Icons\day.ico").Handle)
         .Groups.Add(1).Image = 1
         .ReplaceIcon (LoadPicture("E:\Temp\Icons\week.ico").Handle)
         .Groups.Add(1).Image = 2
    End With
End Sub

In this sample, the LoadPicture().Handle returns the HICON of the icon.

ALL.21:
The PDF virtual printer shows in black the icon's background instead using the white color. The ExPrint's Preview area shows the icons in white background but when sending to the PDF virtual printer they are shown in black so it sounds that the problem is related to PDF.

Change the ExPrint's AsScreen property ( by default, False ) on True like in the following VB sample:

With Print1
    .AsScreen = True
     Set .PrintExt = Control.Object
     .Preview
End With
where the Control is the component being printed.
ALL.22:
The metrics between screen device and print device could be different, so difference may occur, even the same DATA is sent to screen or a printer device. In order to fix, this you can change the ExPrint's AsScreen property ( by default, False ) on True like in the following VB sample:
With Print1
    .AsScreen = True
     Set .PrintExt = Control.Object
     .Preview
End With

where the Control is the component being printed.

ALL.23:
We can get an issue fixed/added/changed as soon as we have a sample and steps to reproduce the problem using the latest released/trial version of the product.

Please follow the steps:

  1. Make sure you are using the latest released/trial version from downloaded from our website. Most of the time, using a newer version may already fix the issue you have.
  2. If the problem still persist with the latest released/trial version, try to create a s i m p l e  s a m p l e and  s t e p s you can reproduce it.
  3. Send us the sample and the steps we can replicate it. If you can provide this sample using the x-script, that would be perfect and fast to get it fixed for us.
  4. Once we have the confirmation that we can replicate it too, you will receive an answer that we have been able to replicate the issue.
  5. If we are still unable to replicate your issue using your sample and steps, we will ask you to get permission for a remote session.
Thanks for your understanding.
ALL.24:
Implementing the OLE Drag and Drop is the same for any programming language, on Windows systems. The drag-and-drop feature of OLE is primarily a shortcut for copying and pasting data. In other words, when your require to pick up an object and drop it to another application or when you need to rearrange the items in a list. This tutorial explains starting a OLE Drag and Drop operation using our UI /COM components in VB, VS C++ 2008 compared with a non-MS product, such as dBASE Plus. The same is for Visual DataFlex, Clarion, Smaltalk, Visual Objects, PowerBuilder, UniPaas and so on  . For /NET assemblies, please check the "Drag-and-Drop operations for /NET assemblies" article.

In order to begin an OLE Drag and Drop operation, the following two steps are required:

  • Set the control's OLEDropMode property on 1.
  • Handle the OLEStartDrag event and call the SetData method of the Data parameter.

If any of this is NOT completed the OLE Drag and Drop can not be initiated. Once you add these, you can see the drag and drop cursor as soon as you click the object and start dragging. 

The code to begin the OLE Drag and Drop should be: 

VB:

Private Sub Form_Load()
    G2antt1.OLEDropMode = 1
End Sub

Private Sub G2antt1_OLEStartDrag(ByVal Data As EXG2ANTTLibCtl.IExDataObject, AllowedEffects As Long)
    Data.SetData "some data to be dragged"
End Sub
C++:
#import <ExG2antt.dll>
using namespace EXG2ANTTLib;

BOOL CDDTestDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	EXG2ANTTLib::IG2anttPtr spG2antt1 = GetDlgItem(IDC_G2ANTT1)->GetControlUnknown();
	spG2antt1->OLEDropMode = EXG2ANTTLib::exOLEDropManual;

	return TRUE;
}

BEGIN_EVENTSINK_MAP(CDDTestDlg, CDialog)
	ON_EVENT(CDDTestDlg, IDC_G2ANTT1, 1002, CDDTestDlg::OLEStartDragG2antt1, VTS_DISPATCH VTS_PI4)
END_EVENTSINK_MAP()

void CDDTestDlg::OLEStartDragG2antt1(LPDISPATCH Data, long* AllowedEffects)
{
	if ( EXG2ANTTLib::IExDataObjectPtr spData = Data )
		spData->SetData( _T("some data to be dragged") );
}
dBASE Plus:
function form_open
   local oG2antt
   oG2antt = this.EXG2ANTT.nativeObject
   oG2antt.OLEDropMode = 1
return ddtutForm::open()

function nativeObject_OLEStartDrag(Data, AllowedEffects)
   Data.SetData("some data to be dragged")
return

These steps show how to initiate a OLE Drag and Drop operation using our UI components. If the OLEDropMode property is present in the control's type library, it means that the control supports the OLE Drag and Drop. The SetData call specifies the data to be carried during the drag and drop. For instance, if you want to drag the item's value you should pass there the values for each cell, or replace the  "some data to be dragged" with your data.

Now, lets change the sample so we can change the order of the listed items. Generally, our UI components provide the Items.ItemPosition property to change the position of the item. The first change we need to do is to replace the SetData call with the handle of the dragged item as in the following samples:

VB:
Private Sub G2antt1_OLEStartDrag(ByVal Data As EXG2ANTTLibCtl.IExDataObject, AllowedEffects As Long)
    AllowedEffects = 2
    Data.SetData G2antt1.Items.FocusItem
End Sub
C++:
void CDDTestDlg::OLEStartDragG2antt1(LPDISPATCH Data, long* AllowedEffects)
{
	*AllowedEffects = 2;
	if ( EXG2ANTTLib::IExDataObjectPtr spData = Data )
	{
		EXG2ANTTLib::IG2anttPtr spG2antt1 = GetDlgItem(IDC_G2ANTT1)->GetControlUnknown();
		spData->SetData( spG2antt1->Items->GetFocusItem() );
	}
}
dBASE Plus:
function nativeObject_OLEStartDrag(Data, AllowedEffects)
   AllowedEffects = 2
   Data.SetData(this.Items.FocusItem)
return
  • The next step is to handle the OLEDragDrop event to perform the change once the user drags the item to a new position, or in other words to change the dragged item's position to the position of the item from the cursor. For that the sample uses the Items.ItemPosition property to change the 
VB:
Private Sub G2antt1_OLEDragDrop(ByVal Data As EXG2ANTTLibCtl.IExDataObject, Effect As Long, ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)
    Dim c As Long, hit As HitTestInfoEnum
    Dim i As Long
    i = G2antt1.ItemFromPoint(-1, -1, c, hit)
    If (i <> 0) Then
        With G2antt1.Items
            .ItemPosition(Data.GetData(1)) = .ItemPosition(i)
        End With
    End If
End Sub

The sample just change the position of the dragged item ( which was stored on Data.SetData during the OLEStartDrag ) with the position of the item at the time the user dropped the cursor.

C++:
BEGIN_EVENTSINK_MAP(CDDTestDlg, CDialog)
	ON_EVENT(CDDTestDlg, IDC_G2ANTT1, 1002, CDDTestDlg::OLEStartDragG2antt1, VTS_DISPATCH VTS_PI4)
	ON_EVENT(CDDTestDlg, IDC_G2ANTT1, 1001, CDDTestDlg::OLEDragDropG2antt1, VTS_DISPATCH VTS_PI4 VTS_I2 VTS_I2 VTS_I4 VTS_I4)
END_EVENTSINK_MAP()

void CDDTestDlg::OLEDragDropG2antt1(LPDISPATCH Data, long* Effect, short Button, short Shift, long X, long Y)
{
	if ( EXG2ANTTLib::IExDataObjectPtr spData = Data )
	{
		EXG2ANTTLib::IG2anttPtr spG2antt1 = GetDlgItem(IDC_G2ANTT1)->GetControlUnknown();
		long c = 0;
		EXG2ANTTLib::HitTestInfoEnum hit = EXG2ANTTLib::exHTCell;
		long i = spG2antt1->GetItemFromPoint( -1, -1, &c, &hit);
		if ( i != 0 )
		{
			EXG2ANTTLib::IItemsPtr spItems = spG2antt1->Items;
			spItems->PutItemPosition( spData->GetData( 1 ), spItems->GetItemPosition( i ) );
		}
	}
}

The sample just change the position of the dragged item ( which was stored on Data.SetData during the OLEStartDrag ) with the position of the item at the time the user dropped the cursor.

dBASE Plus:
function nativeObject_OLEDragDrop(Data, Effect, Button, Shift, X, Y)
   local i, c, hit
   c = 0
   hit = 0
   i = this.ItemFromPoint(-1,-1,c,hit)
   if ( i <> 0 )
      oG2antt = form.EXG2ANTT.nativeObject
      with ( oG2antt )
         TemplateDef = [Dim var_Items,h,i]
         TemplateDef = oG2antt.Items
         TemplateDef = Data.GetData()
         TemplateDef = i
         Template = [var_Items.ItemPosition(h) = var_Items.ItemPosition(i)]
      endwith
   endif
return
The sample just change the position of the dragged item ( which was stored on Data.SetData during the OLEStartDrag ) with the position of the item at the time the user dropped the cursor. Because, the dBASE Plus does not support setting a property with multiple parameters, the code uses the TemplateDef method of the control, to do the Items.ItemPosition(h) =   Items.ItemPosition(i).
ALL.25:
Most of our components support formatting the values. By formatting we mean that instead displaying a  value we can display in the way we desire. Properties such as Column.FormatColumn, Items.FormatCell and so on support formatting. For instance, the currency(100) displays the value 100 as a currency, for instance in US format it will display $100 while for German format will display 100 ?. The format expression supports operators, constants and values as described bellow. From case to case, there are few predefined keywords such as value, which indicates the value to be formatted, the %0, %1, %2, %3, ... indicates variables that could be: the value in a specified column, the value for a specified property of the bar, and so on. If the formatting is using in  properties such as: Items.ItemBar(exBarToolTip), Items.ItemBar(exBarCaption) or Items.ItemBar(exBarExtraCaption) the %C0, %C1, %C2, ... indicates the captions in the cells, and so on/ 

The Exontrol's eXPression component is a syntax-editor that helps you to define, view, edit and evaluate expressions. Using the eXPression component you can easily view or check if the expression you have used is syntactically correct, and you can evaluate what is the result you get giving different values to be tested. The Exontrol's eXPression component can be used as an user-editor, to configure your applications.

For instance:

  • the dbl(value) + 1, adds 1 to giving value.
  • the currency(value) displays the value using the current format for the currency ie, 1000 gets displayed as $1,000.00, for US format
  • the value format '2|.3|,' displays the value using 2 digits, . as decimal separator, grouping by 3 digits using the , as a grouping separator. 
  • the date(value) format `MMM d, yyyy` , returns the date such as Sep 2, 2023, for English format
  • the type(value) in (0,1) ? 'null' : ( dbl(value)<0 ? '<fgcolor=FF0000>'+ (value format '2|.|3,' ) : (dbl(value)>0 ? '<fgcolor=0000FF>+'+(value format '2|.|3,' ): '0.00') ) displays the positive values in blue, being preceded by + sign, negative values in red preceded by - sign, 0 as 0.00 while for null values is displays null. The numbers are displayed using 2 digits, . as decimal separator and grouping by 3 digits by , separator.
  • the longdate(date(value)) converts the value to a date and gets the long format to display the date in the column, ie #1/1/2001# displays instead Monday, January 01, 2001
  • the ((1:=int(0:= (value))) != 0 ? (=:1 + ' day(s)') : '') + (=:1 ? ' ' : '' ) + ((1:=int(0:=((=:0 - =:1 + 1/24/60/60/2)*24))) != 0 ? =:1 + ' hour(s)' : '' ) + (=:1 ? ' ' : '' ) + ((1:=round((=:0 - =:1)*60)) != 0 ? =:1 + ' min(s)' : ''), displays the value in days, hours and minutes
  • the trim((1:=int((0:=value)/365) ? =:1 + ` year(s) ` : ``) + (1:=int((0:=(=:0 - (=:1*365)))/31) ? =:1 + ` month(s) ` : ``) + (1:=int((0:=(=:0 - (=:1*31)))/7) ? =:1 + ` week(s) ` : ``) + (1:=int((0:=(=:0 - (=:1*7)))/1) ? =:1 + ` day(s) ` : ``) + (1:=int((0:=(=:0 - =:1 + 1/24/60/60/2))*24) ? =:1 + ` hour(s) ` : ``) + (1:=int((0:=(=:0*24 - =:1))*60) ? =:1 + ` min(s) ` : ``) + (1:=int((0:=(=:0*60 - =:1))*60) ? =:1 + ` sec(s)` : ``)) displays the value in years, months, weeks, days, hours, minutes and seconds.
  • the date(dateS('3/1/' + year(value)) + ((1:=(((255 - 11 * (year(value) mod 19)) - 21) mod 30) + 21) + (=:1 > 48 ? -1 : 0) + 6 - ((year(value) + int(year(value) / 4)) + =:1 + (=:1 > 48 ? -1 : 0) + 1) mod 7)) computes the Easter Sunday, where the value indicates the year where the Easter Sunday is required. The value should be of date-time type. 

The constants can be represented as:

  • numbers in decimal format ( where dot character specifies the decimal separator ). For instance: -1, 100, 20.45, .99 and so on
  • numbers in hexa-decimal format ( preceded by 0x or 0X sequence ), uses sixteen distinct symbols, most often the symbols 0-9 to represent values zero to nine, and A, B, C, D, E, F (or alternatively a, b, c, d, e, f) to represent values ten to fifteen. Hexadecimal numerals are widely used by computer system designers and programmers. As each hexadecimal digit represents four binary digits (bits), it allows a more human-friendly representation of binary-coded values. For instance, 0xFF, 0x00FF00, and so so.
  • date-time in format #mm/dd/yyyy[ hh:mm:ss]#, For instance, #1/1/2001#, #12/31/1971 11:00#, and so on
  • string, if it starts / ends with any of the ' or ` or " characters. If you require the starting character inside the string, it should be escaped ( preceded by a \ character ). The same for any \ ( escape ) character, it should be preceded by an extra \ character. For instance, `Mihai`, "Filimon", 'has', "\"a quote\"", and so on

The predefined constants are:

  • bias ( BIAS constant), defines the difference, in minutes, between Coordinated Universal Time (UTC) and local time. For example, Middle European Time (MET, GMT+01:00) has a time zone bias of "-60" because it is one hour ahead of UTC. Pacific Standard Time (PST, GMT-08:00) has a time zone bias of "+480" because it is eight hours behind UTC. For instance, date(value - bias/24/60) converts the UTC time to local time, or date(date('now') + bias/24/60) converts the current local time to UTC time. For instance, "date(value - bias/24/60)" converts the value date-time from UTC to local time, while "date(value + bias/24/60)" converts the local-time to UTC time.
  • dpi ( DPI constant ), specifies the current DPI setting. and it indicates the minimum value between dpix and dpiy constants. For instance, if current DPI setting is 100%, the dpi constant returns 1, if 150% it returns 1.5, and so on. For instance, the expression value * dpi returns the value if the DPI setting is 100%, or value * 1.5 in case, the DPI setting is 150%
  • dpix ( DPIX constant ), specifies the current DPI setting on x-scale. For instance, if current DPI setting is 100%, the dpix constant returns 1, if 150% it returns 1.5, and so on. For instance, the expression value * dpix returns the value if the DPI setting is 100%, or value * 1.5 in case, the DPI setting is 150%
  • dpiy ( DPIY constant ), specifies the current DPI setting on x-scale. For instance, if current DPI setting is 100%, the dpiy constant returns 1, if 150% it returns 1.5, and so on. For instance, the expression value * dpiy returns the value if the DPI setting is 100%, or value * 1.5 in case, the DPI setting is 150%

The supported binary arithmetic operators are:

  • * ( multiplicity operator ), priority 5
  • / ( divide operator ), priority 5
  • mod ( reminder operator ), priority 5
  • + ( addition operator ), priority 4 ( concatenates two strings, if one of the operands is of string type )
  • - ( subtraction operator ), priority 4

The supported unary boolean operators are:

  • not ( not operator ), priority 3 ( high priority )

The supported binary boolean operators are:

  • or ( or operator ), priority 2
  • and ( or operator ), priority 1

The supported binary boolean operators, all these with the same priority 0, are :

  • < ( less operator )
  • <= ( less or equal operator )
  • = ( equal operator )
  • != ( not equal operator )
  • >= ( greater or equal operator )
  • > ( greater operator )

The supported binary range operators, all these with the same priority 5, are :

  • a MIN b ( min operator ), indicates the minimum value, so a MIN b returns the value of a, if it is less than b, else it returns b. For instance, the expression value MIN 10 returns always a value greater than 10.
  • a MAX b ( max operator ), indicates the maximum value, so a MAX b returns the value of a, if it is greater than b, else it returns b. For instance, the expression value MAX 100 returns always a value less than 100.

The supported binary operators, all these with the same priority 0, are :

  • := (Store operator),  stores the result of expression to variable. The syntax for := operator is 

    variable := expression

    where variable is a integer between 0 and 9. You can use the =: operator to restore any stored variable ( please make the difference between := and =: ). For instance, (0:=dbl(value)) = 0 ? "zero" : =:0, stores the value converted to double, and prints zero if it is 0, else the converted number. Please pay attention that the := and =: are two distinct operators, the first for storing the result into a variable, while the second for restoring the variable

  • =: (Restore operator),  restores the giving variable ( previously saved using the store operator ). The syntax for =: operator is 

    =: variable

    where variable is a integer between 0 and 9. You can use the := operator to store the value of any expression ( please make the difference between := and =: ). For instance, (0:=dbl(value)) = 0 ? "zero" : =:0, stores the value converted to double, and prints zero if it is 0, else the converted number. Please pay attention that the := and =: are two distinct operators, the first for storing the result into a variable, while the second for restoring the variable

The supported ternary operators, all these with the same priority 0, are :

  • ? ( Immediate If operator ), returns and executes one of two expressions, depending on the evaluation of an expression. The syntax for ? operator is 

expression ? true_part : false_part

, while it executes and returns the true_part if the expression is true, else it executes and returns the false_part. For instance, the %0 = 1 ? 'One' : (%0 = 2 ? 'Two' : 'not found') returns 'One' if the value is 1, 'Two' if the value is 2, and 'not found' for any other value. A n-ary equivalent operation is the case() statement, which is available in newer versions of the component.

The supported n-ary operators are (with priority 5):

  • array (at operator), returns the element from an array giving its index ( 0 base ). The array operator returns empty if the element is found, else the associated element in the collection if it is found. The syntax for array operator is 

expression array (c1,c2,c3,...cn)

, where the c1, c2, ... are constant elements. The constant elements could be numeric, date or string expressions. For instance the month(value)-1 array ('J','F','M','A','M','Jun','J','A','S','O','N','D') is equivalent with month(value)-1 case (default:''; 0:'J';1:'F';2:'M';3:'A';4:'M';5:'Jun';6:'J';7:'A';8:'S';9:'O';10:'N';11:'D')

  • in (include operator), specifies whether an element is found in a set of constant elements. The in operator returns -1 ( True ) if the element is found, else 0 (false) is retrieved. The syntax for in operator is 

expression in (c1,c2,c3,...cn)

, where the c1, c2, ... are constant elements. The constant elements could be numeric, date or string expressions. For instance the value in (11,22,33,44,13) is equivalent with (expression = 11) or (expression = 22) or (expression = 33) or (expression = 44) or (expression = 13). The in operator is not a time consuming as the equivalent or version is, so when you have large number of constant elements it is recommended using the in operator. Shortly, if the collection of elements has 1000 elements the in operator could take up to 8 operations in order to find if an element fits the set, else if the or statement is used, it could take up to 1000 operations to check, so by far, the in operator could save time on finding elements within a collection.

  • switch (switch operator), returns the value being found in the collection, or a predefined value if the element is not found (default). The syntax for switch operator is 

expression switch (default,c1,c2,c3,...,cn)

, where the c1, c2, ... are constant elements, and the default is a constant element being returned when the element is not found in the collection. The constant elements could be numeric, date or string expressions.  The equivalent syntax is "%0 = c 1 ? c 1 : ( %0 = c 2 ? c 2 : ( ... ? . : default) )". The switch operator is very similar with the in operator excepts that the first element in the switch is always returned by the statement if the element is not found,  while the returned value is the value itself instead -1. For instance, the %0 switch ('not found',1,4,7,9,11) gets 1, 4, 7, 9 or 11, or 'not found' for any other value. As the in operator the switch operator uses binary searches for fitting the element, so it is quicker that iif (immediate if operator) alterative.

  • case() (case operator) returns and executes one of n expressions, depending on the evaluation of the expression ( IIF - immediate IF operator is a binary case() operator ). The syntax for case() operator is:

expression case ([default : default_expression ; ] c1 : expression1 ; c2 : expression2 ; c3 : expression3 ;....)

If the default part is missing, the case() operator returns the value of the expression if it is not found in the collection of cases ( c1, c2, ...). For instance, if the value of expression is not any of c1, c2, .... the default_expression is executed and returned. If the value of the expression is c1, then the case() operator executes and returns the expression1. The default, c1, c2, c3, ... must be constant elements as numbers, dates or strings. For instance, the date(shortdate(value)) case (default:0 ; #1/1/2002#:1 ; #2/1/2002#:1; #4/1/2002#:1; #5/1/2002#:1) indicates that only #1/1/2002#, #2/1/2002#,  #4/1/2002# and  #5/1/2002# dates returns 1, since the others returns 0. For instance the following sample specifies the hour being non-working for specified dates: date(shortdate(value)) case(default:0;#4/1/2009# : hour(value) >= 6 and hour(value) <= 12 ; #4/5/2009# : hour(value) >= 7 and hour(value) <= 10 or hour(value) in(15,16,18,22); #5/1/2009# : hour(value) <= 8) statement indicates the working hours for dates as follows:

  • #4/1/2009#, from hours 06:00 AM to 12:00 PM
  • #4/5/2009#, from hours 07:00 AM to 10:00 AM and hours 03:00PM, 04:00PM, 06:00PM and 10:00PM
  • #5/1/2009#, from hours 12:00 AM to 08:00 AM

The in, switch and case() use binary search to look for elements so they are faster then using iif and or expressions. Obviously, the priority of the operations inside the expression is determined by ( ) parenthesis and the priority for each operator. 

The supported conversion unary operators are:

  • type (unary operator) retrieves the type of the object. The type operator may return any of the following: 0 - empty ( not initialized ), 1 - null, 2 - short, 3 - long, 4 - float, 5 - double, 6 - currency, 7 - date, 8 - string, 9 - object, 10 - error, 11 - boolean, 12 - variant, 13 - any, 14 - decimal, 16 - char, 17 - byte, 18 - unsigned short, 19 - unsigned long, 20 - long on 64 bits, 21 - unsigned long on 64 bites. For instance type(%1) = 8 specifies the cells ( on the column with the index 1 ) that contains string values. 
  • str (unary operator) converts the expression to a string. The str operator converts the expression to a string. For instance, the str(-12.54) returns the string "-12.54".
  • dbl (unary operator) converts the expression to a number. The dbl operator converts the expression to a number. For instance, the dbl("12.54") returns 12.54
  • date (unary operator) converts the expression to a date, based on your regional settings. For instance, the date(``) gets the current date ( no time included ), the date(`now`) gets the current date-time, while the date("01/01/2001") returns #1/1/2001#
  • dateS (unary operator) converts the string expression to a date using the format MM/DD/YYYY HH:MM:SS. For instance, the dateS("01/01/2001 14:00:00") returns #1/1/2001 14:00:00#
  • hex (unary operator) converts the giving string from hexa-representation to a numeric value, or converts the giving numeric value to hexa-representation as string. For instance, hex(`FF`) returns 255, while the hex(255) or hex(0xFF) returns the `FF` string. The hex(hex(`FFFFFFFF`)) always returns `FFFFFFFF` string, as the second hex call converts the giving string to a number, and the first hex call converts the returned number to string representation (hexa-representation).�

The bitwise operators for numbers are:

  • a bitand b (binary operator) computes the AND operation on bits of a and b, and returns the unsigned value. For instance, 0x01001000 bitand 0x10111000 returns 0x00001000.
  • a bitor b (binary operator) computes the OR operation on bits of a and b, and returns the unsigned value. For instance, 0x01001000 bitor 0x10111000 returns 0x11111000.
  • a bitxor b (binary operator) computes the XOR ( exclusive-OR ) operation on bits of a and b, and returns the unsigned value. For instance, 0x01110010 bitxor 0x10101010 returns 0x11011000.
  • a bitshift (b) (binary operator) shifts every bit of a value to the left if b is negative, or to the right if b is positive, for b times, and returns the unsigned value. For instance, 128 bitshift 1 returns 64 ( dividing by 2 ) or 128 bitshift (-1) returns 256 ( multiplying by 2 )
  • bitnot ( unary operator ) flips every bit of x, and returns the unsigned value. For instance, bitnot(0x00FF0000) returns 0xFF00FFFF.

The operators for numbers are:

  • int (unary operator) retrieves the integer part of the number. For instance, the int(12.54) returns 12
  • round (unary operator) rounds the number ie 1.2 gets 1, since 1.8 gets 2. For instance, the round(12.54) returns 13
  • floor (unary operator) returns the largest number with no fraction part that is not greater than the value of its argument. For instance, the floor(12.54) returns 12
  • abs (unary operator) retrieves the absolute part of the number ie -1 gets 1, 2 gets 2. For instance, the abs(-12.54) returns 12.54
  • sin (unary operator) returns the sine of an angle of x radians. For instance, the sin(3.14) returns 0.001593.
  • cos (unary operator) returns the cosine of an angle of x radians. For instance, the cos(3.14) returns -0.999999.
  • asin (unary operator) returns the principal value of the arc sine of x, expressed in radians. For instance, the 2*asin(1) returns the value of PI.
  • acos (unary operator) returns the principal value of the arc cosine of x, expressed in radians. For instance, the 2*acos(0) returns the value of PI
  • sqrt (unary operator) returns the square root of x. For instance, the sqrt(81) returns 9.
  • currency (unary operator) formats the giving number as a currency string, as indicated by the control panel. For instance, currency(value) displays the value using the current format for the currency ie, 1000 gets displayed as $1,000.00, for US format.
  • value format 'flags' (binary operator) formats the numeric value with specified flags. The format method formats numeric or date expressions (depends on the type of the value, explained at operators for dates). If flags is empty, the number is displayed as shown in the field "Number" in the "Regional and Language Options" from the Control Panel. For instance the 1000 format '' displays 1,000.00 for English format, while 1.000,00 is displayed for German format. 1000 format '2|.|3|,' will always displays 1,000.00 no matter of settings in the control panel. If formatting the number fails for some invalid parameter, the value is displayed with no formatting. 
    The ' flags' for format operator is a list of values separated by | character such as 'NumDigits|DecimalSep|Grouping|ThousandSep|NegativeOrder|LeadingZero' with the following meanings: 
    • NumDigits - specifies the number of fractional digits, If the flag is missing, the field "No. of digits after decimal" from "Regional and Language Options" is using.
    • DecimalSep - specifies the decimal separator. If the flag is missing, the field "Decimal symbol" from "Regional and Language Options" is using.
    • Grouping - indicates the number of digits in each group of numbers to the left of the decimal separator. Values in the range 0 through 9 and 32 are valid. The most significant grouping digit indicates the number of digits in the least significant group immediately to the left of the decimal separator. Each subsequent grouping digit indicates the next significant group of digits to the left of the previous group. If the last value supplied is not 0, the remaining groups repeat the last group. Typical examples of settings for this member are: 0 to group digits as in 123456789.00; 3 to group digits as in 123,456,789.00; and 32 to group digits as in 12,34,56,789.00. If the flag is missing, the field "Digit grouping" from "Regional and Language Options" indicates the grouping flag.
    • ThousandSep - specifies the thousand separator. If the flag is missing, the field "Digit grouping symbol" from "Regional and Language Options" is using.
    • NegativeOrder - indicates the negative number mode. If the flag is missing, the field "Negative number format" from "Regional and Language Options" is using. The valid values are 0, 1, 2, 3 and 4 with the following meanings:
      • 0 - Left parenthesis, number, right parenthesis; for example, (1.1) 
      • 1 - Negative sign, number; for example, -1.1
      • 2 - Negative sign, space, number; for example, - 1.1
      • 3 - Number, negative sign; for example, 1.1-
      • 4 - Number, space, negative sign; for example, 1.1 -
    • LeadingZero - indicates if leading zeros should be used in decimal fields.  If the flag is missing, the field "Display leading zeros" from "Regional and Language Options" is using. The valid values are 0, 1

The operators for strings are:

  • len (unary operator) retrieves the number of characters in the string. For instance, the len("Mihai") returns 5.
  • lower (unary operator) returns a string expression in lowercase letters. For instance, the lower("MIHAI") returns "mihai"
  • upper (unary operator) returns a string expression in uppercase letters. For instance, the upper("mihai") returns "MIHAI"
  • proper (unary operator) returns from a character expression a string capitalized as appropriate for proper names. For instance, the proper("mihai") returns "Mihai"
  • ltrim (unary operator) removes spaces on the left side of a string. For instance, the ltrim(" mihai") returns "mihai"
  • rtrim (unary operator) removes spaces on the right side of a string. For instance, the rtrim("mihai ") returns "mihai"
  • trim (unary operator) removes spaces on both sides of a string. For instance, the trim(" mihai ") returns "mihai"
  • reverse (unary operator) reverses the order of the characters in the string a. For instance, the reverse("Mihai") returns "iahiM"
  • a startwith b (binary operator) specifies whether a string starts with specified string ( 0 if not found, -1 if found ). For instance "Mihai" startwith "Mi" returns -1
  • a endwith b (binary operator) specifies whether a string ends with specified string ( 0 if not found, -1 if found ). For instance "Mihai" endwith "ai" returns -1
  • a contains b (binary operator) specifies whether a string contains another specified string ( 0 if not found, -1 if found ). For instance "Mihai" contains "ha" returns -1
  • a left b (binary operator) retrieves the left part of the string. For instance "Mihai" left 2 returns "Mi".
  • a right b (binary operator) retrieves the right part of the string. For instance "Mihai" right 2 returns "ai"
  • a lfind b (binary operator) The a lfind b (binary operator) searches the first occurrence of the string b within string a, and returns -1 if not found, or the position of the result ( zero-index ). For instance "ABCABC" lfind "C" returns 2
  • a rfind b (binary operator)  The a rfind b (binary operator) searches the last occurrence of the string b within string a, and returns -1 if not found, or the position of the result ( zero-index ). For instance "ABCABC" rfind "C" returns 5.
  • a mid b (binary operator) retrieves the middle part of the string a starting from b ( 1 means first position, and so on ). For instance "Mihai" mid 2 returns "ihai"
  • a count b (binary operator) retrieves the number of occurrences of the b in a. For instance "Mihai" count "i" returns 2.
  • a replace b with c (double binary operator) replaces in a the b with c, and gets the result. For instance, the "Mihai" replace "i" with "" returns "Mha" string, as it replaces all "i" with nothing.
  • a split b (binary operator) splits the a using the separator b, and returns an array. For instance, the weekday(value) array 'Sun Mon Thu Wed Thu Fri Sat' split ' ' gets the weekday as string. This operator can be used with the array.
  • a like b (binary operator) compares the string a against the pattern b. The pattern b may contain wild-characters such as *, ?, # or [] and can have multiple patterns separated by space character. In order to have the space, or any other wild-character inside the pattern, it has to be escaped, or in other words it should be preceded by a \ character. For instance value like `F*e` matches all strings that start with F and ends on e, or value like `a* b*` indicates any strings that start with a or b character.
  • a lpad b (binary operator) pads the value of a to the left with b padding pattern. For instance, 12 lpad "0000" generates the string "0012".
  • a rpad b (binary operator) pads the value of a to the right with b padding pattern. For instance, 12 lpad "____" generates the string "12__".
  • a concat b (binary operator) concatenates the a (as string) for b times. For instance, "x" concat 5, generates the string "xxxxx".

The operators for dates are:

  • time (unary operator) retrieves the time of the date in string format, as specified in the control's panel. For instance, the time(#1/1/2001 13:00#) returns "1:00:00 PM"
  • timeF (unary operator) retrieves the time of the date in string format, as "HH:MM:SS". For instance, the timeF(#1/1/2001 13:00#) returns "13:00:00"
  • shortdate (unary operator) formats a date as a date string using the short date format, as specified in the control's panel. For instance, the shortdate(#1/1/2001 13:00#) returns "1/1/2001"
  • shortdateF (unary operator) formats a date as a date string using the "MM/DD/YYYY" format. For instance, the shortdateF(#1/1/2001 13:00#) returns "01/01/2001"
  • dateF (unary operator) converts the date expression to a string expression in "MM/DD/YYYY HH:MM:SS" format. For instance, the dateF(#01/01/2001 14:00:00#) returns #01/01/2001 14:00:00#
  • longdate (unary operator) formats a date as a date string using the long date format, as specified in the control's panel. For instance, the longdate(#1/1/2001 13:00#) returns "Monday, January 01, 2001"
  • year (unary operator) retrieves the year of the date (100,...,9999). For instance, the year(#12/31/1971 13:14:15#) returns 1971
  • month (unary operator) retrieves the month of the date ( 1, 2,...,12 ). For instance, the month(#12/31/1971 13:14:15#) returns 12.
  • day (unary operator) retrieves the day of the date ( 1, 2,...,31 ). For instance, the day(#12/31/1971 13:14:15#) returns 31
  • yearday (unary operator) retrieves the number of the day in the year, or the days since January 1st ( 0, 1,...,365 ). For instance, the yearday(#12/31/1971 13:14:15#) returns 365
  • weekday (unary operator) retrieves the number of days since Sunday ( 0 - Sunday, 1 - Monday,..., 6 - Saturday ). For instance, the weekday(#12/31/1971 13:14:15#) returns 5.
  • hour (unary operator) retrieves the hour of the date ( 0, 1, ..., 23 ). For instance, the hour(#12/31/1971 13:14:15#) returns 13
  • min (unary operator) retrieves the minute of the date ( 0, 1, ..., 59 ). For instance, the min(#12/31/1971 13:14:15#) returns 14
  • sec (unary operator) retrieves the second of the date ( 0, 1, ..., 59 ). For instance, the sec(#12/31/1971 13:14:15#) returns 15
  • value format 'flags' (binary operator) formats a date expression with specified flags. The format method formats numeric (depends on the type of the value, explained at operators for numbers) or date expressions. If not supported, the value is formatted as a number (the date format is supported by newer version only). The flags specifies the format picture string that is used to form the date. Possible values for the format picture string are defined below. For instance, the date(value) format `MMM d, yyyy` returns "Sep 2, 2023"

    The following table defines the format types used to represent days:

    • d, day of the month as digits without leading zeros for single-digit days (8)
    • dd, day of the month as digits with leading zeros for single-digit days (08)
    • ddd, abbreviated day of the week as specified by the current locale ("Mon" in English)
    • dddd, day of the week as specified by the current locale ("Monday" in English)

    The following table defines the format types used to represent months:

    • M, month as digits without leading zeros for single-digit months (4)
    • MM, month as digits with leading zeros for single-digit months (04)
    • MMM, abbreviated month as specified by the current locale ("Nov" in English)
    • MMMM, month as specified by the current locale ("November" for English)

    The following table defines the format types used to represent years:

    • y, year represented only by the last digit (3)
    • yy, year represented only by the last two digits. A leading zero is added for single-digit years (03)
    • yyy, year represented by a full four or five digits, depending on the calendar used. Thai Buddhist and Korean calendars have five-digit years. The "yyyy" pattern shows five digits for these two calendars, and four digits for all other supported calendars. Calendars that have single-digit or two-digit years, such as for the Japanese Emperor era, are represented differently. A single-digit year is represented with a leading zero, for example, "03". A two-digit year is represented with two digits, for example, "13". No additional leading zeros are displayed.
    • yyyy, behaves identically to "yyyy"

    The following table defines the format types used to represent era:

    • g, period/era string formatted as specified by the CAL_SERASTRING value (ignored if there is no associated era or period string)
    • gg, period/era string formatted as specified by the CAL_SERASTRING value (ignored if there is no associated era or period string)

    The following table defines the format types used to represent hours:

    • h, hours with no leading zero for single-digit hours; 12-hour clock
    • hh, hours with leading zero for single-digit hours; 12-hour clock
    • H, hours with no leading zero for single-digit hours; 24-hour clock
    • HH, hours with leading zero for single-digit hours; 24-hour clock

    The following table defines the format types used to represent minutes:

    • m, minutes with no leading zero for single-digit minutes
    • mm, minutes with leading zero for single-digit minutes

    The following table defines the format types used to represent seconds:

    • s, seconds with no leading zero for single-digit seconds
    • ss, seconds with leading zero for single-digit seconds

    The following table defines the format types used to represent time markers:

    • t, one character time marker string, such as A or P
    • tt, multi-character time marker string, such as AM or PM

The expression supports also immediate if ( similar with iif in visual basic, or ? : in C++ ) ie cond ? value_true : value_false, which means that once that cond is true the value_true is used, else the value_false is used. Also, it supports variables, up to 10 from 0 to 9. For instance, 0:="Abc" means that in the variable 0 is "Abc", and =:0 means retrieves the value of the variable 0. For instance, the len(%0) ? ( 0:=(%1+%2) ? currency(=:0) else `` ) : `` gets the sum between second and third column in currency format if it is not zero, and only if the first column is not empty. As you can see you can use the variables to avoid computing several times the same thing ( in this case the sum %1 and %2 .

Other known operators for auto-numbering are ( supported by Column.FormatColumn, Items.FormatCell properties ):

  • number index 'format', indicates the index of the item. The first added item has the index 0, the second added item has the index 1, and so on. The index of the item remains the same even if the order of the items is changed by sorting. For instance, 1 index '' gets the index of the item starting from 1 while 100 index '' gets the index of the item starting from 100. The number indicates the starting index, while the format is a set of characters to be used for specifying the index. If the format is missing, the index of the item is formatted as numbers. For instance: 1 index 'A-Z' gets the index as A, B, C... Z, BA, BB, ... BZ, CA, ... . The 1 index 'abc' gives the index as: a,b,c,ba,bb,bc,ca,cb,cc,.... You can use other number formatting function to format the returned value. For instance 1 index '' format '0||2|:' gets the numbers grouped by 2 digits and separated by : character.

    In the following screen shot the FormatColumn("Col 1")  = "1 index ''"

    In the following screen shot the FormatColumn("Col 1")  = "1 index 'A-Z'"

     

  • number apos 'format' indicates the absolute position of the item. The first displayed item has the absolute position 0 ( scrolling position on top  ), the next visible item is 1, and so on.  The number indicates the starting position, while the format is a set of characters to be used for specifying the position. For instance, 1 apos '' gets the absolute position of the item starting from 1, while 100 apos '' gets the position of the item starting from 100. If the format is missing, the absolute position of the item is formatted as numbers.

    In the following screen shot the FormatColumn("Col 1")  = "1 apos ''"

    In the following screen shot the FormatColumn("Col 1")  = "1 apos 'A-Z'"

  • number pos 'format' indicates the relative position of the item. The relative position is the position of the visible child item in the parent children collection. The number indicates the starting position, while the format is a set of characters to be used for specifying the position. For instance, 1 pos '' gets the relative position of the item starting from 1, while 100 pos '' gets the relative position of the item starting from 100. If the format is missing, the relative position of the item is formatted as numbers. The difference between pos and opos can be seen while filtering the items in the control. For instance, if no filter is applied to the control, the pos and opos gets the same result. Instead, if the filter is applied, the opos gets the position of the item in the list of unfiltered items, while the pos gets the position of the item in the filtered list.

    In the following screen shot the FormatColumn("Col 2")  = "'<b>' + 1 pos '' + '</b> ' + value"

    In the following screen shot the FormatColumn("Col 2")  = "'<b>' + 1 pos 'A-Z' + '</b> ' + value"

  • number opos 'format' indicates the relative old position of the item. The relative old position is the position of the child item in the parent children collection. The number indicates the starting position, while the format is a set of characters to be used for specifying the position.For instance, 1 pos '' gets the relative position of the item starting from 1, while 100 pos '' gets the relative position of the item starting from 100. If the format is missing, the relative position of the item is formatted as numbers. The difference between pos and opos can be seen while filtering the items in the control. For instance, if no filter is applied to the control, the pos and opos gets the same result. Instead, if the filter is applied, the opos gets the position of the item in the list of unfiltered items, while the pos gets the position of the item in the filtered list.
  • number rpos 'format' indicates the relative recursive position of the item. The recursive position indicates the position of the parent items too. The relative position is the position of the visible child item in the parent children collection. The number indicates the starting position, while the format is of the following type "delimiter|format|format|...". If the format is missing, the delimiter is . character, and the positions are formatted as numbers. The format is applied consecutively to each parent item, from root to item itself.

    In the following screen shot the FormatColumn("Col 1")  = "1 rpos ''"

    In the following screen shot the FormatColumn("Col 1")  = "1 rpos ':|A-Z'"

    In the following screen shot the FormatColumn("Col 1")  = "1 rpos '.|A-Z|'"

    In the following screen shot the FormatColumn("Col 1")  = "1 apos ''" and FormatColumn("Col 2")  = "'<b><font Tahoma;10>' + 1 rpos '.|A-Z|' + '</font></b> ' + value"

  • number rindex 'format', number rapos 'format' and number ropos 'format' are working similar with number rpos 'format', excepts that they gives the index, absolute position, or the old child position.

Here's a few samples of using the value expressions:

  • Column.ComputedField = "currency(dbl(%0))"
    • Displays the column using current currency format with values from the first column.
  • Column.FormatColumn = "type(value) in (0,1) ? 'null' : ( dbl(value)<0 ? '<fgcolor=FF0000>'+ (value format '2|.|3|,|1' ) : (dbl(value)>0 ? '<fgcolor=0000FF>+'+(value format '2|.|3|,' ): '0.00') )"
    • Displays null for empty cells, 0.00 for 0 value, +value in blue for positive values, and -value for negative values in red.
  • Items.FormatCell(h,0) = "(value format '2|.|3|,|1|1')"
    • Displays the cell using 2 decimals, 3 digit for grouping, no matter of the options in the regional setting.  
  • Chart.AddNonworkingDate("not(month(value) in (3,4)) ? 0 : ( floor(value)=floor(date(dateS('3/1/' + year(value)) + ((1:=(((255 - 11 * (year(value) mod 19)) - 21) mod 30) + 21) + (=:1 > 48 ? -1 : 0) + 6 - ((year(value) + int(year(value) / 4)) + =:1 + (=:1 > 48 ? -1 : 0) + 1) mod 7))))")
    • Adds the Easter Sunday, as a non-working date in a repetitive expression.
  • Items.ItemBar(exBarCaption) = "<b><%=%9 + '/' + %C0%></b><br>Duration: <%=(%2-%1)%><br>Working: <%=%258%><br><upline><dotline>Progress: <%=round(100*%12)+'%'%>
    • Indicates that the bar's caption displays the exBarKey, the value on the first column and the duration as being the different between exBarEnd - exBarStart values of the current bar.
  • Chart.ZoomOnFlyCaption = "<c><b><%=%C0%></b><br><solidline><upline><b>Start</b>:<%=%1%><br><b>End</b>:<%=%2%><br><b>Duration</b>:<%=round(%2-%1) + ' days'%><br><b>Working</b>:<%=%258%> days" 
    • Displays in the zoom-on-fly caption the following information:

       

      • the cell's caption on the first column
      • the starting point of the bar from the bar 
      • the ending point of the bar from the bar
      • the duration or length of the bar as being the difference between start and ending point of the bar
      • the working units as days.

      the zoom on fly caption shows as following:

  • Chart.ZoomOnFlyCaption = "<br><c><b><font ;12><%=%C0 + ' / <fgcolor=00FF00>' + %3%></font></fgcolor></b><br><solidline><upline><b>Start</b>:<%=%1%><br><b>End</b>:<%=%2%><br><b>Duration</b>:<%=round(%2-%1) + ' days'%><br><b>Working</b>:<%='<b>' + int(%258) + '</b> days' + (0:=(%258 - int(%258)) ? (' <fgcolor=FF0000><b>' + round(24 * =:0) + '</b> hours') : '') %>" 
    • Displays in the zoom-on-fly caption the following information:

       

      • the cell's caption on the first column / the caption of the bar from the point
      • the starting point of the bar from the bar 
      • the ending point of the bar from the bar
      • the duration or length of the bar as being the difference between start and ending point of the bar
      • the working units as days and hours.

      the zoom on fly caption shows as following:

ALL.26:
Most of our components support built-in HTML format. This means that you can display your strings using font or color attributes, bold, italics, and so on. 

Currently, the Exontrol's built-in HTML format supports the following HTML tags:

  • <b> ... </b> displays the text in bold.
  • <i> ... </i> displays the text in italics.
  • <u> ... </u> underlines the text.
  • <s> ... </s> Strike-through text
  • <a id;options> ... </a> displays an anchor element that can be clicked. An anchor is a piece of text or some other object (for example an image) which marks the beginning and/or the end of a hypertext link.The <a> element is used to mark that piece of text (or inline image), and to give its hypertextual relationship to other documents. The control fires the AnchorClick(AnchorID, Options) event when the user clicks the anchor element. The FormatAnchor property customizes the visual effect for anchor elements.

    The ExButton, ExComboBox, ExG2antt, ExGantt, ExGrid, ExHTML, ExLabel, ExList, ExOrgChart, ExplorerTree, ExSchedule, ExSurface, ExSwimlane, ExTree controls support expandable HTML captions feature. The expandable-captions allow you to expand(show)/collapse(hide) different information using <a ;exp=> or <a ;e64=> anchor tags. The exp/e64 field of the anchor stores the HTML line/lines to show once the user clicks/collapses/expands the caption.

    • exp, stores the plain text to be shown once the user clicks the anchor, such as <a ;exp=show lines>
    • e64, encodes in BASE64 the HTML text to be shown once the user clicks the anchor, such as <a ;e64=gA8ABmABnABjABvABshIAOQAEAAHAAGESikWio+ABzABohp3iELABpABuABljYAgRhAEaFsqAAvAEsjUCmUEg0IhUMhUPjQAAEBA>+</a> that displays show lines- in gray when the user clicks the + anchor. The gA8ABmABnABjABvABshIAOQAEAAHAAGESikWio+ABzABohp3iELABpABuABljYAgRhAEaFsqAAvAEsjUCmUEg0IhUMhUPjQAAEBA string encodes the <fgcolor 808080>show lines<a>-</a></fgcolor> The Decode64Text/Encode64Text methods of the eXPrint can be used to decode/encode e64 fields.

    Any ex-HTML caption can be transformed to an expandable-caption, by inserting the anchor ex-HTML tag. For instance, <solidline><b>Header</b></solidline><br>Line1<r><a ;exp=show lines>+</a><br>Line2<br>Line3 shows the Header in underlined and bold on the first line and Line1, Line2, Line3 on the rest. The show lines is shown instead of Line1, Line2, Line3 once the user clicks the + sign.

  • <font face;size> ... </font> displays portions of text with a different font and/or different size. For instance, the <font Tahoma;12>bit</font> draws the bit text using the Tahoma font, on size 12 pt. If the name of the font is missing, and instead size is present, the current font is used with a different size. For instance, <font ;12>bit</font> displays the bit text using the current font, but with a different size.
  • <fgcolor color> ... </fgcolor> or <fgcolor=color> ... </fgcolor> displays text with a specified foreground color. The color field accepts values in various formats: RRGGBB format, which represents the red(RR), green(GG), and blue(BB) values in hexadecimal format; named colors defined in CSS; or RGB format specified as rgb(RED,GREEN,BLUE), where RED, GREEN, and BLUE range from 0 to 255.
  • <bgcolor color> ... </bgcolor> or <bgcolor=color> ... </bgcolor> displays text with a specified background color. The color field accepts values in various formats: RRGGBB format, which represents the red(RR), green(GG), and blue(BB) values in hexadecimal format; named colors defined in CSS; or RGB format specified as rgb(RED,GREEN,BLUE), where RED, GREEN, and BLUE range from 0 to 255.
  • <solidline color> ... </solidline> or <solidline=color> ... </solidline> draws a solid-line on the bottom side of the current text-line, of specified RGB color. The <solidline> ... </solidline> draws a black solid-line on the bottom side of the current text-line. The color field accepts values in various formats: RRGGBB format, which represents the red(RR), green(GG), and blue(BB) values in hexadecimal format; named colors defined in CSS; or RGB format specified as rgb(RED,GREEN,BLUE), where RED, GREEN, and BLUE range from 0 to 255.
  • <dotline color> ... </dotline> or <dotline=color> ... </dotline> draws a dot-line on the bottom side of the current text-line, of specified RGB color. The <dotline> ... </dotline> draws a black dot-line on the bottom side of the current text-line. The color field accepts values in various formats: RRGGBB format, which represents the red(RR), green(GG), and blue(BB) values in hexadecimal format; named colors defined in CSS; or RGB format specified as rgb(RED,GREEN,BLUE), where RED, GREEN, and BLUE range from 0 to 255.
  • <upline> ... </upline> draws the line on the top side of the current text-line (requires <solidline> or <dotline>).
  • <r> right aligns the text
  • <c> centers the text
  • <br> forces a line-break
  • <img>number[:width]</img> inserts an icon inside the text. The number indicates the index of the icon being inserted. Use the Images method to assign a list of icons to your chart. The last 7 bits in the high significant byte of the number expression indicates the identifier of the skin being used to paint the object. Use the Add method to add new skins to the control. If you need to remove the skin appearance from a part of the control you need to reset the last 7 bits in the high significant byte of the color being applied to the part. The width is optional and indicates the width of the icon being inserted. Using the width option you can overwrite multiple icons getting a nice effect. By default, if the width field is missing, the width is 18 pixels.
  • <img>key[:width]</img> inserts a custom size picture into the text being previously loaded using the HTMLPicture property. The Key parameter indicates the key of the picture being displayed. The Width parameter indicates a custom size, if you require to stretch the picture, else the original size of the picture is used.
  • & glyph characters as &amp; ( & ), &lt; ( < ), &gt; ( > ),  &qout; ( " ) and &#number; ( the character with specified code ), For instance, the &#8364; displays the EUR character. The & ampersand is only recognized as markup when it is followed by a known letter or a #character and a digit. For instance if you want to display <b>bold</b> in HTML caption you can use &lt;b&gt;bold&lt;/b&gt;
  • <off offset> ... </off> defines the vertical offset to display the text/element. The offset parameter defines the offset to display the element. This tag is inheritable, so the offset is keep while the associated </off> tag is found. You can use the <off offset> HTML tag in combination with the <font face;size> to define a smaller or a larger font to be displayed. For instance: Text with <font ;7><off 6>subscript displays the text such as: Text with subscript The Text with <font ;7><off -6>superscript displays the text such as: Text with subscript
  • <gra color;mode;blend> ... </gra> defines a gradient text. The text color or <fgcolor> defines the starting gradient color, while the color field defines the ending color, 808080 if missing as gray. The color field accepts values in various formats: RRGGBB format, which represents the red(RR), green(GG), and blue(BB) values in hexadecimal format; named colors defined in CSS; or RGB format specified as rgb(RED,GREEN,BLUE), where RED, GREEN, and BLUE range from 0 to 255. The mode is a value between 0 and 4, 1 if missing, and blend could be 0 or 1, 0 if missing. The <font> HTML tag can be used to define the height of the font. Any of the color, mode or blend field may not be specified. The <gra> with no fields, shows a vertical gradient color from the current text color to gray (808080). For instance the <font ;18><gra FFFFFF;1;1>gradient-center</gra></font> generates the following picture:
  • <out color;width> ... </out> shows the text with outlined characters, where color field defines the outline color, 808080 if missing as gray, width indicates the size of the outline, 1 if missing. The color field accepts values in various formats: RRGGBB format, which represents the red(RR), green(GG), and blue(BB) values in hexadecimal format; named colors defined in CSS; or RGB format specified as rgb(RED,GREEN,BLUE), where RED, GREEN, and BLUE range from 0 to 255. The text color or <fgcolor> defines the color to show the inside text. The <font> HTML tag can be used to define the height of the font. For instance the <font ;31><out 000000><fgcolor=FFFFFF>outlined</fgcolor></out></font> generates the following picture:
  • <sha color;width;offset> ... </sha> define a text with a shadow, where color defines the shadow color, 808080 if missing as gray, width indicates the size of shadow, 4 if missing, and offset indicates the offset from the origin to display the text's shadow, 2 if missing. The color field accepts values in various formats: RRGGBB format, which represents the red(RR), green(GG), and blue(BB) values in hexadecimal format; named colors defined in CSS; or RGB format specified as rgb(RED,GREEN,BLUE), where RED, GREEN, and BLUE range from 0 to 255. The text color or <fgcolor> defines the color to show the inside text. The <font> HTML tag can be used to define the height of the font.  For instance the <font ;31><sha>shadow</sha></font> generates the following picture:

    or  <font ;31><sha 404040;5;0><fgcolor=FFFFFF>outline anti-aliasing</fgcolor></sha></font> gets:

For instance, the following HTML caption

<font Segoe Print>This is a bit of text with a <b>different</b> font</font> <upline><dotline>left 1<r><b>right</b> 2 <img>1</img><c><a><s>center <img>pic1:64</img> picture</s><r></a><img>2</img> left 3 <c>center<r><b>right</b> 4

 generates the following screen shot:

Some of our components, such as ExG2antt, can combine the current HTML format with other HTML tags such as:

  • <%identifier%> tag that indicates a value in the chart. For instance the <%d%> indicates the day of the month in one or two numeric digits, as needed (1 to 31). This option is valid for properties such as Level.Label, Level.ToolTip, Chart.Label, Chart.LabelToolTip, Chart.FormatDate, Chart.OverviewToolTip, Chart.ToolTip, InsideZoomFormat.InsideLabel, InsideZoomFormat.OwnerLabel, Note.PartText and Note.Text. 
For instance, the following HTML in Chart.Label property: 
Chart.Level(0).Label = "<%loc_ldate%><r>Week: <b><%ww%></b><||><||>256"
Chart.Level(1).Label = "<%d%><font ;6> (<%d3%>)</font>"

 generates the following screen shot:

  • <%=formula%> tag indicates that the object displays the result of the giving formula. The formula supports value formatting. Inside the formula the %0, %1, ... indicates the value of corresponding  property of the bar, such as %0 specifies the exBarName, %1 exBarStart, and so on. Also, the %C0, %C1, ... indicates the cell's value. The bar belongs to an item, which could display several cells/ The %CIndex helps you to use the cell's caption in the bar's caption or tool tip. For instance the Items.ItemBar(exBarToolTip) = "Duration of <b><%=%9 + ' of ' + %C0%></b> is <%=(%2-%1)%> days" specifies that the bar's tooltip shows the duration of the bar such as : "Duration of K1 of Task1 is 3 days." where the %9 indicates the exBarKey, %C0 indicates the cell's caption on the column 0, while %2 is exBarEnd and %1 is exBarStart. Using the <%=formula%> html TAG, you will be able to format the bar's tooltip/caption to display its content based on the current properties of the bar, without having to redefine the tooltip or caption once a bar is updated. This option is valid for Items.ItemBar(exBarToolTip), Items.ItemBar(exBarCaption) or Items.ItemBar(exBarExtraCaption)
For instance, the following HTML in ItemBar(exBarCaption) property: 
Items.ItemBar(exBarCaption) = "<b><%=%9 + '/' + %C0%></b><br>Duration: <%=(%2-%1)%><br>Working: <%=%258%><br><upline><dotline>Progress: <%=round(100*%12)+'%'%>"

 generates the following screen shot:

 

ALL.27:
The /COM version provides the Picture and PictureDiplay properties that may be used to place a picture on the control's background. For instance, the VB6 browser or the VB6's LoadPicture won't let you add or load a PNG picture, instead you can use the LoadPicture predefined function of the x-script language, when using the Template or ExecuteTemplate property, like shown in the following samples:

The following statements are equivalent, and loads a PNG on the control's background:

  • .Template = "Picture = LoadPicture(`E:\picture.png`)"
  • .Picture = Gantt1.ExecuteTemplate("loadpicture(`E:\picture.png`)")

The Template and the Picture are properties of one of the exontrol's component. 

The LoadPicture method of the x-script template supports:

  • the file name of the picture file ( aka c:\picture.bmp )
  • a BASE64-encoded string with the picture's content. The string must be generated by the eXImages tool, by dragging the picture file to the middle panel of the too ( there you can see the Drag here files such of .bmp, .gif, .ebn.... (.

The following samples use the eXGant's ExecuteTemplate property to load a PNG and assign it to the Picture property using a PNG file:

VBA
With Gantt1
	.Picture = Gantt1.ExecuteTemplate("loadpicture(`E:\picture.png`)")
End With
VB6
With Gantt1
	.Picture = Gantt1.ExecuteTemplate("loadpicture(`E:\picture.png`)")
End With
VB.NET
With Exgantt1
	.Picture = Exgantt1.ExecuteTemplate("loadpicture(`E:\picture.png`)")
End With
VB.NET for /COM
With AxGantt1
	.Picture = AxGantt1.ExecuteTemplate("loadpicture(`E:\picture.png`)")
End With
C++
EXGANTTLib::IGanttPtr spGantt1 = GetDlgItem(IDC_GANTT1)->GetControlUnknown();
spGantt1->PutPicture(IPictureDispPtr(((ObjectPtr)(spGantt1->ExecuteTemplate("loadpicture(`E:\\picture.png`)")))));
C++ Builder
Gantt1->Picture = (IPictureDisp*)(Gantt1->ExecuteTemplate("loadpicture(`E:\\picture.png`)"));
C#
exgantt1.Picture = (exgantt1.ExecuteTemplate("loadpicture(`E:\\picture.png`)") as Object);
JavaScript
<OBJECT classid="clsid:09C0C400-3A0F-4CD3-8B93-8D42FCE66726" id="Gantt1"></OBJECT>

<SCRIPT LANGUAGE="JScript">
	Gantt1.Picture = Gantt1.ExecuteTemplate("loadpicture(`E:\\picture.png`)")
</SCRIPT>
C# for /COM
(axGantt1.GetOcx() as EXGANTTLib.Gantt).Picture = (axGantt1.ExecuteTemplate("loadpicture(`E:\\picture.png`)") as Object);
X++ (Dynamics Ax 2009)
public void init()
{
	super()
	exgantt1.Picture(exgantt1.ExecuteTemplate("loadpicture(`E:\\picture.png`)"))
}
VFP
with thisform.Gantt1
	.Picture = thisform.Gantt1.ExecuteTemplate("loadpicture(`E:\picture.png`)")
endwith
dBASE Plus
local oGantt

oGantt = form.Activex1.nativeObject
oGantt.Picture = oGantt.ExecuteTemplate("loadpicture(`E:\picture.png`)")
XBasic (Alpha Five)
Dim oGantt as P

oGantt = topparent:CONTROL_ACTIVEX1.activex
oGantt.Picture = oGantt.ExecuteTemplate("loadpicture(`E:\picture.png`)")
Delphi 8 (.NET only)
with AxGantt1 do
begin
	(GetOcx() as EXGANTTLib.Gantt).Picture := (AxGantt1.ExecuteTemplate('loadpicture(`E:\picture.png`)') as Object);
end
Delphi (standard)
with Gantt1 do
begin
	Picture := (IUnknown(Gantt1.ExecuteTemplate('loadpicture(`E:\picture.png`)')) as _TLB.Object);
end
Visual Objects
oDCOCX_Exontrol1:Picture := oDCOCX_Exontrol1:ExecuteTemplate("loadpicture(`E:\picture.png`)")
PowerBuilder
OleObject oGantt

oGantt = ole_1.Object
oGantt.Picture = oGantt.ExecuteTemplate("loadpicture(`E:\picture.png`)")
ALL.28:
The DataSource property links the control's content to a database. By default, it loads data as a flat table, without creating a hierarchy. When a new item or record is added to the control's view, the AddItem event is triggered. The following tutorials will demonstrate how to load hierarchies using the DataSource property with a flat table or list. Use the LinesAtRoot property with a non-zero value (zero, by default ), to allow root items to display the +/- signs. The following samples are applicable to components like ExCascadeTree,ExComboBox, ExGrid, ExG2antt, ExGantt or ExTree.

Please be aware that the ExG2Host control comes with built-in support for loading hierarchies from tables, utilizing the parent-id field. This control is an extension of the ExG2antt control, which itself extends the ExGrid, and ultimately extends ExTree. By specifying the Data(exItemsParentID) property, you can designate the field responsible for delineating the hierarchy within the control.

The following methods may uses any of the following events, properties and methods:

  • event AddItem (Item as HITEM), occurs once a new item is added to the control's list collection. The Item indicates the handle of the newly inserted item.
  • event BeforeExpandItem (Item as HITEM, Cancel as Variant), occurs once an item is about to be expanded. The Item indicates the handle of the item to be expanded.
  • method PutItems (Items as Variant, [Parent as Variant]), loads an array of values as a child of an item. The array(Items) can be one or two- dimensional. If the array is one-dimensional, the control requires one column being added before calling the PutItems method. If the Items parameter indicates a two-dimensional array, the first dimension defines the columns, while the second defines the number of items to be loaded. For instance, a(2,100) means 2 columns and 100 items. The Parent specifies the handle of the item where the array is being inserted, or 0 if missing.
  • property AllowGroupBy, collects the rows with the same value on a specified field, and shows them as children of the found value. Available for ExCascadeTree, ExGrid or ExG2antt only.
  • method Items.InsertItem ([Parent as HITEM], [UserData as Variant], [Value as Variant]) inserts a new item, and returns a handle to the newly created item. The Parent indicates the item's handle that indicates the parent item where the newly item is inserted. The UserData indicates the item's extra data (Items.ItemData property). The Value indicates the cell's value on the first column, or a safe array that holds values for each column.
  • method Items.InsertControlItem (Parent as HITEM, ControlID as String, [License as Variant]), inserts an inner ActiveX control that can hold another grid, list tree or gantt control, which can bound to another database. The Parent indicates the handle of the parent item where the ActiveX will be inserted. The ControlID can be a prog ID, a CLSID, a URL, a reference to an Active document , a fragment of HTML. The License indicates the runtime license key for the component being inserted.
  • property Items.CellValue([Item as Variant], [ColIndex as Variant]) gets or sets the value of an item on a specified column ( equivalent of Items.CellCaption for eXTree, eXGantt). The Item indicates the item's handle. The ColIndex indicates the cell's handle or the column's index, a string expression that indicates the column's caption or the column's key. If the Item parameter is missing or it is zero ( 0 ), the ColIndex parameter is the handle of the cell being accessed. 
  • method Items.SetParent (Item as HITEM, NewParent as HITEM) changes at runtime the parent of giving item. The Item indicates the item's handle. The NewParent indicates the handle of the newly parent item.
  • property Items.FindItem (Value as Variant, [ColIndex as Variant], [StartIndex as Variant])  property finds a value within the list. The Value indicates the value/caption that is searched for. The ColIndex indicates the column's caption, or a long expression that indicates the column's index. The StartIndex indicates the index of item from where the searching starts.
  • property Items.ItemHasChildren (Item as HITEM) specifies whether the item should display a +- sign for expanding/collapsing the item. The Item indicates the item's handle.
  • property Items.ItemData(Item as HITEM) associates any extra data to an item

Also, most of the following methods use:

  • property DataSource as Object, loads data source into the control. The DataSource property binds the control to an ADO, ADODB or DAO recordset. In the context of .NET, the DataSource property is used to determine or assign the data source being presented by the control. Initially, this property is set to an empty object. The acceptable types for the DataSource property include DataTable, DataView, DataSet, DataViewManager, any component implementing the IListSource interface, or any component implementing the IList interface.

Here's a few ways of loading your flat data as a hierarchy:

  1. (PutItems) The database includes a field that indicates the parent for the record ( parent-id relation, single data source )
  2. (InsertItem) The database includes a field that indicates the parent for the record ( parent-id relation, single data source )
  3. (SetParent) The database includes a field that indicates the parent for the record ( parent-id relation, single data source )
  4. (VirtualTree) The sub-items use the same columns and are loaded on the fly, when the user expands a specified item ( single data source )
  5. (InsertControlItem) The items loads the master table, and the sub-items loads the detail table, using the InsertControlItem method. The child items are loading on the fly, when the user expands a specified item ( multiple data source )
  6. (AllowGroupBy) Collects the rows with the same value on a specified field, and shows them as children of the found value, using the AllowGroupBy property (single data source )
  7. (Two or more tables) Loads the hierarchy using two or more tables (multiple data source)

Please be aware that the ExG2Host control comes with built-in support for loading hierarchies from tables, utilizing the parent-id field. This control is an extension of the ExG2antt control, which itself extends the ExGrid, and ultimately extends ExTree. By specifying the Data(exItemsParentID) property, you can designate the field responsible for delineating the hierarchy within the control.

Here's how the flat table shows:

  • (PutItems) The database includes a field that indicates the parent for the record ( parent-id relation, single data source )

datasource-putitems-tree table

There are two ways to load the hierarchy using the PutItems method:
  1. Load the entire hierarchy by specifying the parent-id relationship in the format "parent;IDColumn;ParentIDColumn" for the Parent parameter
  2. Load the hierarchy dynamically as items are expanded

Load the entire hierarchy by specifying the parent-id relationship in the format "parent;IDColumn;ParentIDColumn" for the Parent parameter

Pass the index of the column containing the row identifiers and the index of the column containing the parent identifiers in the format ";IDColumn;ParentIDColumn," as shown in the following example:
Private Sub Form_Load()
  Dim rsItems As ADODB.Recordset
  Set rsItems = CreateObject("ADODB.Recordset")
  With Tree1
      .BeginUpdate
      .LinesAtRoot = exLinesAtRoot
      rsItems.Open "SELECT * FROM MyData ORDER By ParentKey", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & App.Path & "\test.accdb", adOpenKeyset, adLockPessimistic
      For i = 0 To rsItems.Fields.Count - 1
          .Columns.Add rsItems.Fields(i).Name
      Next
      .PutItems rsItems.GetRows(), ";" & .Columns.Item("Key").Index & ";" & .Columns.Item("ParentKey").Index
      .EndUpdate
  End With
End Sub
or
Private Sub Form_Load()
  Dim rsCols As ADODB.Recordset, rsItems As ADODB.Recordset
  Dim sConnection As String
  sConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & App.Path & "\test.accdb"
  Set rsCols = CreateObject("ADODB.Recordset")
  Set rsItems = CreateObject("ADODB.Recordset")
  rsCols.Open "SELECT * FROM MyData WHERE 1 = 0", sConnection, adOpenKeyset, adLockPessimistic
  With Tree1
      .BeginUpdate
      .LinesAtRoot = exLinesAtRoot
      .DataSource = rsCols ' adds the columns of the table
      rsItems.Open "SELECT * FROM MyData ORDER By ParentKey", sConnection, adOpenKeyset, adLockPessimistic
      .PutItems rsItems.GetRows(), ";" & .Columns.Item("Key").Index & ";" & .Columns.Item("ParentKey").Index ' adds the hierarchy defined by ParentKey-Key columns
      .EndUpdate
  End With
End Sub
where the statement "DataSource = rsCols" adds the columns of the table (with "WHERE 1 = 0" to ensure that only the header of the table is loaded), which are required before calling the PutItems method.

Load the hierarchy dynamically as items are expanded.

The idea is to load items with no parent, using the DataSource, and load child items on the fly, using the PutItems method, when an item gets expanded. This method requires no ordering of the "ParentKey" field, and it is the fastest method, as it loads the items on the fly. This method requires an index on the "ParentKey" field. so we can quickly find out if a record has any child records. The "ParentKey" is the name of the column that holds the parent key, and the "Key" is the column that holds the key for each record.
Private Declare Function GetTickCount Lib "kernel32" () As Long

Dim sConnection As String
Dim rsSeek As ADODB.Recordset

Private Function GetChildOf(ByVal key As Variant) As ADODB.Recordset
    Dim rs As ADODB.Recordset
    Set rs = CreateObject("ADODB.Recordset")
        rs.Open "SELECT * FROM MyData WHERE ParentKey='" & key & "'", sConnection, adOpenKeyset, adLockPessimistic
    Set GetChildOf = rs
End Function

Private Sub Form_Load()
    Dim nTick As Long
    nTick = GetTickCount()
    With Tree1
        .BeginUpdate
        .LinesAtRoot = exLinesAtRoot
        
        sConnection = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & App.Path & "\test.accdb"
        Set rsSeek = CreateObject("ADODB.Recordset")
        rsSeek.CursorLocation = adUseServer
        rsSeek.Open "MyData", sConnection, , , adCmdTableDirect
        rsSeek.Index = "ParentKey"
        
        .DataSource = GetChildOf("")
       
        .EndUpdate
    End With
    Me.Caption = GetTickCount - nTick & " ms"
End Sub

Private Sub Tree1_AddItem(ByVal Item As EXTREELibCtl.HITEM)
    With Tree1.Items
        rsSeek.Seek Array(.CellCaption(Item, "Key"))
        Dim bHasChildren As Boolean
        bHasChildren = Not rsSeek.EOF
        .ItemHasChildren(Item) = bHasChildren
        .ItemData(Item) = bHasChildren
    End With
End Sub

Private Sub Tree1_BeforeExpandItem(ByVal Item As EXTREELibCtl.HITEM, Cancel As Variant)
    With Tree1.Items
        If Not (.ItemData(Item) = 0) Then
            .ItemData(Item) = 0
            Tree1.PutItems GetChildOf(.CellCaption(Item, "Key")).GetRows(), Item
        End If
    End With
End Sub
where the GetChildOf method returns a Recordset that contains all child elements of specified key. The AddItem event changes the item's ItemHasChidlren property if it has children elements, and when the BeforeExpandItem event occurs, the control loads child elements using the control's PutItems method 
  • (InsertItem) The database includes a field that indicates the parent for the record ( parent-id relation, single data source )

insertitem-tree table

The idea is to enumerate the records in the table one by one, insert the item as child of specified "ParentKey", and storing the value of the inserted item with associated "Key". This method requires ordering of the "ParentKey" field. This method requires a Dictionary, Hash, Map object. The "ParentKey" is the name of the column that holds the parent key, and the "Key" is the column that holds the key for each record.
Private Declare Function GetTickCount Lib "kernel32" () As Long

Private Sub Form_Load()
    Dim nTick As Long
    nTick = GetTickCount()
    With Tree1
        .BeginUpdate
        .LinesAtRoot = exLinesAtRoot
        Set rs = CreateObject("ADOR.Recordset")
        rs.Open "SELECT * FROM MyData ORDER BY ParentKey", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & App.Path & "\test.accdb", 3, 3
        For Each c In rs.Fields
            .Columns.Add c.Name
        Next
        Dim n As New Dictionary
        Dim id As Long, pid As Long, nCount As Long
        id = .Columns("Key").Index
        pid = .Columns("ParentKey").Index
        nCount = .Columns.Count
        With .Items
            While Not rs.EOF
                Dim hItem As hItem, hParent As hItem, vParent As Variant
                hParent = 0
                vParent = rs(pid).Value
                If (n.Exists(vParent)) Then
                    hParent = n(vParent)
                End If
                hItem = .InsertItem(hParent, , rs(0).Value)
                For j = 1 To nCount - 1
                    .CellCaption(hItem, j) = rs(j).Value
                Next
                n.Add rs(id).Value, hItem
               rs.MoveNext
            Wend
        End With
        .EndUpdate
    End With
    Me.Caption = GetTickCount - nTick & " ms"
End Sub
where n is a dictionary that associates the "Key" with the handle of the item in the control. 
  • (SetParent) The database includes a field that indicates the parent for the record ( parent-id relation, single data source ).

datasource-setparent-tree table

You need to add a handler for AddItem event, and call the following code:

With Grid1.Items
    .SetParent Item, .FindItem(.CellValue(Item, "ParentKey"), "Key")
End With
where the Item is the parameter of the AddItem event, the "ParentKey" is the name of the column that holds the parent key, and the "Key" is the column that holds the key for each record. The code just change the parent of the current record to the associated item. The SetParent method changes the parent of specified item. 

!! The SQL to be passed to the DataSource property should look as "SELECT * FROM table ORDER BY ParentKey", so the items with no parent are listed first, else your data will be listed as a flat table. In other words, the table to be passed to the DataSource should list parent records first, so any time an item should change its parent, its parent item is already added. This method is not the fastest.

The following x-script sample is a template you can use for eXTree ( or any other ), in your eXHelper, to covert the sample to your programming language:

handle AddItem(Item)
{
	Items
	{
		SetParent(Item, FindItem(CellCaption(Item, "ReportsTo"),"EmployeeID"))
	}
}

BeginUpdate
Dim rs
LinesAtRoot = -1 ' exLinesAtRoot(-1)
ColumnAutoResize = False
ContinueColumnScroll = False
rs = CreateObject("ADOR.Recordset")
{
	' Change the Path to the SAMPLE.MDB if nothing is displayed
	Open("SELECT * FROM Employees ORDER BY ReportsTo","Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program Files\Exontrol\ExGrid\Sample\SAMPLE.MDB", 3, 3 )
}
DataSource = rs
Items.ExpandItem(0) = True
EndUpdate

and you should get something like:

  • (VirtualTree) The sub-items use the same columns and are loaded on the fly, when the user expands a specified item ( single data source )

putitems-tree table

1. You need to add a handler for AddItem event, and call the following code:

Dim iAdding As Long

With Grid1.Items
    If (iAdding = 0) Then
        .ItemHasChildren(Item) = True
        .ItemData(Item) = 0
    End If
End With

where the Item is the parameter of the AddItem event. The code just add a + sign to each newly item, so if the user will expand the item, the BeforeExpandItem will be called as follows. The iAdding global variable prevents adding the +/- items to sub-child items, and it is also used bellow in BeforeExpandItem, so items being inserted through the PutItems method are ignored by the AddItem event.

2. You need to add a handler for BeforeExpandItem event, and call the following code:

With Grid1.Items
    If (.ItemData(Item) = 0) Then
        .ItemData(Item) = 1
        Set rs = CreateObject("ADOR.Recordset")
        With rs
            .Open "table", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=database" 3, 3
        End With
        iAdding = iAdding + 1
            Grid1.PutItems rs.GetRows(), Item
        iAdding = iAdding - 1
    End If
End With

This snippet of code adds new child items using the PutItems method of the component, where the Item is the handle of the item being expanded. The GetRows method of the ADO recordset returns all records to a safe collection that can be passed to the PutItems method. In the same manner, you can use the InsertItem to insert a single item as a sub-item, like Items.InsertItem(Item,...), and then you can use the Items.CellValue property to specify the values for different columns. 

In addition, if you are using the eXGantt/Gantt or the eXG2antt/Grid-Gantt components, you can use the AddItem event to add bars associated to the record as in the following sample:

With G2antt1
     With .Items
          AddBar Item,"Task",.CellValue(Item,"Start"),.CellValue(Item,"End")
     End With
End With

where the Item is the parameter of the AddItem event. The "Start" and "End" is the name of the columns that contains the starting and ending dates for the bar to be added. The "Task" is the name of the bar to be inserted. This sample just adds a new "Task" bar for each record found, and use the "Start" and "End" fields in the record to specify the limit of the bar.

  • (InsertControlItem) The items loads the master table, and the sub-items loads the detail table, using the InsertControlItem method. The child items are loading on the fly, when the user expands a specified item ( multiple data source )

insertcontrolitem-tree table

1. You need to add a handler for AddItem event, and call the following code:

Private Sub Grid1_AddItem(ByVal Item As EXGRIDLibCtl.HITEM)
    With Grid1.Items
        If (Len(.ItemControlID(Item)) = 0) Then
            .ItemHasChildren(Item) = True
            .ItemData(Item) = 0
        End If
    End With
End Sub

the AddItem event adds a +/- button for each item being loaded by the master's DataSource call. The ItemData property is initialized with 0, and change to 1, when the item is first expanded.

2. You need to add a handler for BeforeExpandItem event, and call the following code:

Private Sub Grid1_BeforeExpandItem(ByVal Item As EXGRIDLibCtl.HITEM, Cancel As Variant)
    With Grid1.Items
        If (.ItemData(Item) = 0) Then
            .ItemData(Item) = 1
            With .ItemObject(.InsertControlItem(Item, "Exontrol.Grid"))
                .BeginUpdate
                    .ColumnAutoResize = False
                    Set rs = CreateObject("ADOR.Recordset")
                    With rs
                        .Open "table", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" & App.Path & "\testSubGrid2007.accdb", 3, 3
                    End With
                    .DataSource = rs
                .EndUpdate
            End With
        End If
    End With
End Sub

the BeforeExpandItem event insert an inner control ( Exontrol.Grid ), and assigns a new datasource ( detail table ), to expanding item. The code just inserts another control "Exontrol.Grid", and sets the DataSource to a new recordset. The "table" can be your SQL sequence such as SELECT * FROM TABLE WHERE ID = Value, where the any value in the current item could be taken using the CellValue property, such as Items.CellValue(Item."ID" ) get's the value of the cell in the Column ID. It is not mandatory you to create a new recordset using the "CreateObject" method. You can use ADO or DAO it depends on what programming language you are using the component.

The sample shows how the master control loads data using the DataSource property, and adds a inner control, when the user expands the item.

The following function retrieves the handle of the item from the cursor (the function checks the master and inner controls). The gObject, c and hit parameters are passed by reference, so if the returned result is different than zero, the gObject indicates the control where the item is hosted, the c indicates the index of the column, while the hit paramater specifies the hit-test code.

Private Function InsideItem(ByRef gObject As Object, ByRef c As Long, ByRef hit As HitTestInfoEnum) As Long
    Dim i As Long
    i = gObject.ItemFromPoint(-1, -1, c, hit)
    If (i <> 0) Then
        If (IsEmpty(gObject.Items.ItemObject(i))) Then
            InsideItem = i
            Exit Function
        End If
        Set gObject = gObject.Items.ItemObject(i)
        With gObject
            i = gObject.ItemFromPoint(-1, -1, c, hit)
            InsideItem = i
        End With
    End If
End Function

The following snippet of code, show how you can use the InsideItem function:

Private Sub Grid1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    Dim c As Long, hit As HitTestInfoEnum, i As Long
    Dim g As Object
    Set g = Grid1.Object
    i = InsideItem(g, c, hit)
    Debug.Print g.Items.CellValue(i, c)
End Sub
  • (AllowGroupBy) Collects the rows with the same value on a specified field, and shows them as children of the found value, using the AllowGroupBy property ( single data source )

group-by-single column table

group-by-two columns table

1. You need to set the AllowGroupBy property on True.

2. Run the form, and drag any column to the control's sort bar, and so you get the tree-hierarchy on the fly.

3. The same way you drag the columns to the sortbar, you can define the hierarchy by code programmatically. You can use the SortBarVisible property to show or hide the control's sortbar.

  • (Two or more tables) Loads the hierarchy using two or more tables (multiple data source)

Let's say we have two tables tblPart and tblBOM (fields and values) as described:

tblPart (fields)

PartId = autoincrement part record primary key.
PartNumber
Desription
UnitOfMeasure

with the values such as:

PartId,PartNumber,Desription,UnitofMeasure
1,100001,Car,EA
2,100002,AxleWheelAssembly,EA
3,100003,Wheel,EA
4,100004,Axle,EA
5,100005,Body,EA
6,100006,Airplane,EA
7,100007,Wing,EA
8,100008,LandingGearAssy,EA
9,100009,AirplaneWheel,EA

tblBOM (fields)

BOMId = autoincrement BOM record primary key
ParentPartNumber = the id of the parent part corresponding to a tblPartIDPK in tblPart
ChildPartNumber = the id of the child part corresponding to a tblPartIDPK in tblPart
QuantyPerUnit

with the values such as:

BOMid,ParentID,ChildID,QuantityPerUnit
1,100001,100002,2 (Parent=Car,Child=WheelAxleAssembly,QuantityPerUnit=2) 
2,100001,100005,1 (Parent= Car,Child=Body,QuanityPerUnit=1)
3,100002,100004,1 (Parent=WheelAxleAssembly,Child=Axle,QuantityperUnit=1)
4,100002,100003,2 (Parent=WheelAxleAssembly,Child=Wheel,QuantityPerUnit=2)
5,100006,100007,1 (Parent=Airplane,Child=Wing,QuantityPerUnit=1)
6,100006,100008,3 (Parent=Airplane,Child=LandingGearAssy,QuantityPerUnit=3)
7,100008,100009,2 (Parent=LandingGearAssy,Child=AirplaneWheel,QuantityPerUnit=2)

The following VBA sample enumerates the tblBOM table and adds a child-item for each record found. The parent of each item is created/determined at runtime based on the ParentPartNumber field.

Option Compare Database
Dim tree As EXTREELib.tree
Dim tblPart As Recordset
Dim tblBOM As Recordset

Function GetParent(ByVal parentID) As hItem
    Dim hParent
    hParent = tree.Items.FindItemData(parentID)
    If (hParent = 0) Then
        hParent = tree.Items.InsertItem(0, parentID, Array(GetDescription(parentID), 1, GetUnit(parentID))) ' insert a not-already added parent
    End If
    GetParent = hParent
End Function

Function GetUnit(ByVal partID) As String
    tblPart.FindFirst "PartNumber = '" + Trim(partID) + "'"
    GetUnit = IIf(tblPart.EOF, "", tblPart("UnitOfMeasure").Value) ' returns the unit associated with the parent identifier
End Function

Function GetDescription(ByVal partID) As String
    tblPart.FindFirst "PartNumber = '" + Trim(partID) + "'"
    GetDescription = IIf(tblPart.EOF, "", tblPart("Description").Value) ' returns the description associated with the parent identifier
End Function

Private Sub Form_Load()
    Set tree = Tree1.Object
    Set tblPart = CurrentDb.OpenRecordset("tblPart", dbOpenDynaset)
    Set tblBOM = CurrentDb.OpenRecordset("tblBOM", dbOpenDynaset)
    
    With tree
        .BeginUpdate
            ' Specify general options for the control
            .MarkSearchColumn = False
            .LinesAtRoot = exLinesAtRoot
            
            ' Add the Description, Quantity and Unit columns
            .Columns.Add "Description"
            .Columns.Add "Quantity"
            .Columns.Add "Unit"
            
            ' Add a child item for each record within the tblBOM
            With .Items
                While (Not tblBOM.EOF)
                    .InsertItem GetParent(tblBOM("ParentPartNumber").Value), tblBOM("ChildPartNumber").Value, Array(GetDescription(tblBOM("ChildPartNumber").Value), tblBOM("QuantyPerUnit").Value, GetUnit(tblBOM("ChildPartNumber").Value)) ' insert a child-item
                    tblBOM.MoveNext
                Wend
                .ExpandItem(0) = True ' Expand all items
            End With
        .EndUpdate
    End With
End Sub

See Also:

Tips for Accelerating Data Loading into Controls

ALL.29:
The control's DataSource property binds the giving recordset with the control. 

Setting the DataSource property may fire one of the following exceptions: 

  • The recordset must support the bookmarks. ( Supports( adBookmark ) = True )
  • In order to bind the control to a recordset, the recordset needs support for bookmarks.

if the giving recordset does not support bookmarks. When you open a Recordset object, each of its records has a unique bookmark. To save the bookmark for the current record, assign the value of the Bookmark property to a variable. To quickly return to that record at any time after moving to a different record, set the Recordset object's Bookmark property to the value of that variable.

The Bookmark functionality is missing in MySQL connection, unless the the ADO's CursorLocation property is not set on adUseClient. Setting the CursorLocation property must be done prior to Open method like in the following sample:

With Grid1
    Set rs = CreateObject("ADODB.Recordset")
    With rs
       .CursorLocation = 3 ' adUseClient
        .Open "City", "Driver={MySQL ODBC 5.3 UNICODE Driver};Server=localhost;Database=world;Uid=root;Pwd=1234", 3, 3
    End With
    .DataSource = rs
End With
ALL.30:
By default, the control's LoadXML/SaveXML methods loads/saves data of the control, not properties that change the control's appearance like colors, visibility, and so on.

Instead, you can extent this behavior by loading/saving your data to the same XML document like explained bellow:

SaveXML extension

  • Create a "MSXML.DOMDocument" object
  • Save the control's data to the newly created IXMLDOMDocument object, using the control's SaveXML(xml) method
  • Add additional nodes, attributes to the IXMLDOMDocument object, to save additional properties of the component
  • Save the IXMLDOMDocument object to a file or URL, using the IXMLDOMDocument's save method

LoadXML extension

  • Create a "MSXML.DOMDocument" object
  • Load the IXMLDOMDocument object from a file or URL, using the IXMLDOMDocument's load method
  • Load the control's data from the IXMLDOMDocument object, using the control's LoadXML(xml) method
  • Looks for additional nodes, and load them accordingly

The following VB sample defines the SaveXML subroutine, to save the ExG2antt's Chart.OverviewVisible property:

Private Sub SaveXML(ByVal g As Object, ByVal f As String)
    Dim xml As Object
    Set xml = CreateObject("MSXML.DOMDocument")
    
    g.SaveXML xml ' Let the control saves its data to the IXMLDOMDocument object
    
    With xml.firstChild.appendChild(xml.createNode(1, "Additional", "")).Attributes ' Adds the 'Additional' node, under the 'Content' node
        Dim a As Object
        Set a = xml.createAttribute("Chart_OverviewVisible")
        a.Value = g.Chart.OverviewVisible
        .setNamedItem a ' Create and adds a new attribute 'Chart_OverviewVisible' to 'Additional' node's Attributes to save the value of the Chart.OverviewVisible property
    End With
    
    xml.save f ' Saves IXMLDOMDocument object to a file/url
End Sub

The following VB sample defines the LoadXML subroutine, to load the ExG2antt's Chart.OverviewVisible property:

Private Sub LoadXML(ByVal g As Object, ByVal f As String)
    Dim xml As Object
    Set xml = CreateObject("MSXML.DOMDocument")
    
    xml.Load f  ' Loads IXMLDOMDocument object from a file/url
    
    With g
        .BeginUpdate
            .LoadXML xml    ' Lets the control loads its data
            
            Dim c As Object
            For Each c In xml.firstChild.childNodes
                If (c.nodeName = "Additional") Then ' Looks for the "Additional" child node on the 'Content' node
                    With c.Attributes
                        Dim a As Object
                        Set a = .getNamedItem("Chart_OverviewVisible") ' Looks for the 'Chart_OverviewVisible' attribute to be assigned to Chart.OverviewVisible property
                        If Not (a Is Nothing) Then
                            g.Chart.OverviewVisible = a.Value
                        End If
                    End With
                End If
            Next
        .EndUpdate
    End With
    
End Sub

These samples adds/loads an "Additional" node under the "Content" node ( base element ), and save/load the control's property to an attribute. The sample can be extended to save/load any additional property.

The XML format will look as follows:

<Content Author="Exontrol" ... >
	<DateFormat Separator ... />
	<TimeFormat Separator ... />
	<Chart FirstVisibleDate ... >
		...
	</Chart>
	<Columns>
		...
	</Columns>
	<Items>
		...
	</Items>
	<Additional Chart_OverviewVisible="-1"/>
</Content>

Having these, instead calling directly the control's SaveXML method, you need to call the SaveXML control, file/url, and to load the control's data using the XML, you need to call LoadXML control, file/url

ALL.31:
Using the BackgroundExt / BackgroundExtValue property you have unlimited options to show any HTML text, images, colors, EBNs, patterns, frames anywhere on the object's background. For instance, let's say you need to display more colors on the object's background, or just want to display an additional caption or image to a specified location on the object's background. The EBN String Format defines the UI parts of the EBN to be applied on the object's background. The EBN is a set of UI elements that are built as a tree where each element is anchored to its parent element. The idea is as follows: first you need to decide the layout of the UI to put on the object's background, using the BackgroundExt property, and next ( if required ), you can change any property of any part of the background extension to a new value. In other words, let's say you have the same layout to be applied to some of your objects, so you specify the BackgroundExt to be the same for them, and next use the BackgroundExtValue property to change particular properties ( like back-color, size, position, anchor ) for different objects.

In this article you will find:

The EBN String Format syntax in BNF notation is defined like follows:

<EBN> ::= <elements> | <root> "(" [<elements>] ")"
<elements> ::= <element> [ "," <elements> ]
<root> ::= "root" [ <attributes> ] | [ <attributes> ]
<element> ::= <anchor> [ <attributes> ] [ "(" [<elements>] ")" ]
<anchor> ::= "none" | "left" | "right" | "client" | "top" | "bottom"
<attributes> ::= "[" [<client> ","] <attribute> [ "," <attributes> ] "]"
<client> ::= <expression> | <expression> "," <expression> "," <expression> "," <expression>
<expression> ::= <number> | <number> "%"
<attribute> ::= <backcolor> | <text> | <wordwrap> | <align> | <pattern> | <patterncolor> | <frame> | <framethick> | <data> | <others>
<equal> ::= "="
<digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<decimal> ::= <digit><decimal>
<hexadigit> ::= <digit> | "A" | "B"  "C" | "D" | "E"  "F"
<hexa> ::= <hexadigit><hexa>
<number> ::= <decimal> | "0x" <hexa>
<color> ::= <rgbcolor> | number
<rgbcolor> ::= "RGB" "(" <number> "," <number> "," <number> ")"
<string> ::= "`" <characters> "`" | "'" <characters> "'" | " <characters> "
<characters> ::= <char>|<characters>
<char> ::= <any_character_excepts_null>
<backcolor> ::= "back" <equal> <color>
<text> ::= "text" <equal> <string>
<align> ::= "align" <equal> <number>
<pattern> ::= "pattern" <equal> <number>
<patterncolor> ::= "patterncolor" <equal> <color>
<frame> ::= "frame" <equal> <color>
<data> ::= "data" <equal> <number> | <string>
<framethick> ::= "framethick"
<wordwrap> ::= "wordwrap"

Others like: pic, stretch, hstretch, vstretch, transparent, from, to are reserved for future use only.

Here's a few easy samples:

  • "[pattern=6]", shows the BDiagonal pattern on the object's background.
  • "[frame=RGB(255,0,0),framethick]", draws a red thick-border around the object.
  • "[frame=RGB(255,0,0),framethick,pattern=6,patterncolor=RGB(255,0,0)]", draws a red thick-border around the object, with a patter inside.
  • "[[patterncolor=RGB(255,0,0)](none[(4,4,100%-8,100%-8),pattern=0x006,patterncolor=RGB(255,0,0),frame=RGB(255,0,0),framethick])]", draws a red thick-border around the object, with a patter inside, with a 4-pixels wide padding:
  • "top[4,back=RGB(0,0,255)]", draws a blue line on the top side of the object's background, of 4-pixels wide.
  • "[text=`caption`,align=0x22]", shows the caption string aligned to the bottom-right side of the object's background.
  • "[text=`<img>flag</img>`,align=0x11]" shows the flag picture and the sweden string aligned to the bottom side of the object.
  • "left[10,back=RGB(255,0,0)]", draws a red line on the left side of the object's background, of 10-pixels wide.
  • "bottom[50%,pattern=6,frame]", shows the BDiagonal pattern with a border arround on the lower-half part of the object's background.
  • "root[text=`caption <b>2`,align=0x22](client[text=`caption <b>1`,align=0x20])", shows the caption 1 aligned to the bottom-left side, and the caption 2 to the bottom-right side

A complex sample will be arranging the colors as in the following picture:

So we need to define the BackgroundExt property such as:

"left[10%](top[90%,back=RGB(0,0,0)]),top[30%,back=RGB(254,217,102)],client[back=RGB(91,156,212)]"

In the Builder, the this EBN String look as:

so, if we apply to our object we got:

Now, lets say we have the following request to layout the colors on the objects:

We define the BackgroundExt property such as:

 "top[30%,back=RGB(253,218,101)],client[back=RGB(91,157,210)],none[(0%,0%,10%,100%)](top[90%,back=RGB(0,0,0)])"

and it looks as:

so, if we apply to our object we got:

The attributes you can define for any part of the EBN are:

  • first argument between [], equivalent of BackgroundExtValue( Index, exClientExt (2) ) 

Specifies the position/size of the object, depending on the object's anchor. The syntax of the exClientExt is related to the exAnchorExt value. For instance, if the object is anchored to the left side of the parent ( exAnchorExt = 1 ), the exClientExt specifies just the width of the part in pixels/percents, not including the position. In case, the exAnchorExt is client, the exClientExt has no effect. Sample1: "none[(25%,25%,50%,50%),back=RGB(255,0,0)]", Sample2: "right[50%,back=RGB(255,0,0)]", Sample3: "client[text=`<b>caption`]". The client has no position or size.

Based on the exAnchorExt value the exClientExt is:

  • 0 (none, the object is not anchored to any side), the format of the exClientExt is "left,top,width,height" ( as string ) where (left,top) margin indicates the position where the part starts, and the (width,height) pair specifies its size. The left, top, width or height could be any expression (+,-,/ or * ) that can include numbers associated with pixels or percents. For instance: "25%,25%,50%,50%" indicates the middle of the parent object, and so when the parent is resized the client is resized accordingly. The "50%-8,50%-8,16,16" value specifies that the size of the object is always 16x16 pixels and positioned on the center of the parent object.
  • 1 (left, the object is anchored to left side of the parent), the format of the exClientExt is width ( string or numeric ) where width indicates the width of the object in pixels, percents or a combination of them using +,-,/ or * operators. For instance: "50%" indicates the half of the parent object, and so when the parent is resized the client is resized accordingly. The 16 value specifies that the size of the object is always 16 pixels. The 16D value specifies that the size of the object is always 16 pixels on DPI scale of 100%, and, 24 pixels on DPI scale of 150% ( 16 * 150 / 100 ) 
  • 2 (right, the object is anchored to right side of the parent object), the format of the exClientExt is width ( string or numeric ) where width indicates the width of the object in pixels, percents or a combination of them using +,-,/ or * operators. For instance: "50%" indicates the half of the parent object, and so when the parent is resized the client is resized accordingly. The 16 value specifies that the size of the object is always 16 pixels. The 16D value specifies that the size of the object is always 16 pixels on DPI scale of 100%, and, 24 pixels on DPI scale of 150% ( 16 * 150 / 100 )
  • 3 (client, the object takes the full available area of the parent), the exClientExt has no effect.
  • 4 (top, the object is anchored to the top side of the parent object), the format of the exClientExt is height ( string or numeric ) where height indicates the height of the object in pixels, percents or a combination of them using +,-,/ or * operators. For instance: "50%" indicates the half of the parent object, and so when the parent is resized the client is resized accordingly. The 16 value specifies that the size of the object is always 16 pixels. The 16D value specifies that the size of the object is always 16 pixels on DPI scale of 100%, and, 24 pixels on DPI scale of 150% ( 16 * 150 / 100 )
  • 5 (bottom, the object is anchored to bottom side of the parent object), the format of the exClientExt is height ( string or numeric ) where height indicates the height of the object in pixels, percents or a combination of them using +,-,/ or * operators. For instance: "50%" indicates the half of the parent object, and so when the parent is resized the client is resized accordingly. The 16 value specifies that the size of the object is always 16 pixels. The 16D value specifies that the size of the object is always 16 pixels on DPI scale of 100%, and, 24 pixels on DPI scale of 150% ( 16 * 150 / 100 )

Sample: 50% indicates half of the parent, 25 indicates 25 pixels, 25D indicates 25 pixels on DPI 100%, or 50%-8 indicates 8-pixels left from the center of the parent.

(String/Numeric expression)

  • back, equivalent of BackgroundExtValue( Index, exBackColorExt (1) )

Indicates the background color / EBN color to be shown on the part of the object. Sample: "root[back=RGB(255,0,0)]".

(Color/Numeric expression, The last 7 bits in the high significant byte of the color indicate the identifier of the skin being used )

  • none, left, right, client, top or bottom, equivalent of BackgroundExtValue( Index, exAnchorExt (3) )

Specifies the object's alignment relative to its parent. Sample: "right[50%,back=RGB(255,0,0)]"

The valid values for exAnchorExt are:

  • 0 (none), the object is not anchored to any side,
  • 1 (left), the object is anchored to left side of the parent, 
  • 2 (right), the object is anchored to right side of the parent object, 
  • 3 (client), the object takes the full available area of the parent, 
  • 4 (top), the object is anchored to the top side of the parent object, 
  • 5 (bottom), the object is anchored to bottom side of the parent object

(Numeric expression)  

  • text, equivalent of BackgroundExtValue( Index, exTextExt (4) )

Specifies the HTML text to be displayed on the object. Sample: "right[50%,text=`<b>caption`]"

(String expression)

  • wordwrap, equivalent of BackgroundExtValue( Index, exTextExtWordWrap (5) )

Specifies that the object is wrapping the text. The exTextExt value specifies the HTML text to be displayed on the part of the EBN object. This property has effect only if there is a text assigned to the part using the exTextExt flag. Sample: "right[36,text=`This is a bit of text that should break the line`,wordwrap]"

(Boolean expression)

  • align, equivalent of BackgroundExtValue( Index, exTextExtAlignment (6) )

Indicates the alignment of the text on the object. The exTextExt value specifies the HTML text to be displayed on the part of the EBN object. This property has effect only if there is a text assigned to the part using the exTextExt flag. Sample: "left[50%,text=`caption`,align=0x11]"

The valid values for exTextExtAlignment are:

  • 0, ( hexa 0x00, Top-Left ), Text is vertically aligned at the top, and horizontally aligned on the left.
  • 1, ( hexa 0x01, Top-Center ), Text is vertically aligned at the top, and horizontally aligned at the center.
  • 2, ( hexa 0x02, Top-Right ), Text is vertically aligned at the top, and horizontally aligned on the right.
  • 16, ( hexa 0x10, Middle-Left ), Text is vertically aligned in the middle, and horizontally aligned on the left.
  • 17, ( hexa 0x11, Middle-Center  ), Text is vertically aligned in the middle, and horizontally aligned at the center.
  • 18, ( hexa 0x12, Middle-Right  ), Text is vertically aligned in the middle, and horizontally aligned on the right.
  • 32, ( hexa 0x20, Bottom-Left  ), Text is vertically aligned at the bottom, and horizontally aligned on the left.
  • 33, ( hexa 0x21, Bottom-Center ), Text is vertically aligned at the bottom, and horizontally aligned at the center.
  • 34, ( hexa 0x22, Bottom-Right ), Text is vertically aligned at the bottom, and horizontally aligned on the right.

(Numeric expression)

  • pattern, equivalent of BackgroundExtValue( Index, exPatternExt (7) )

Indicates the pattern to be shown on the object. The exPatternColorExt specifies the color to show the pattern. Sample: "root[pattern=0x006]"

The valid values for exPatternExt are:

  • 0, ( hexa 0x000, Empty ), The pattern is not visible
  • 1, ( hexa 0x001, Solid ),
  • 2, ( hexa 0x002, Dot ),
  • 3, ( hexa 0x003, Shadow ),
  • 4, ( hexa 0x004, NDot ),
  • 5, ( hexa 0x005, FDiagonal ),
  • 6, ( hexa 0x006, BDiagonal )
  • 7, ( hexa 0x007, DiagCross ),
  • 8, ( hexa 0x008, Vertical ),
  • 9, ( hexa 0x009, Horizontal ),
  • 10, ( hexa 0x00A, Cross ),
  • 11, ( hexa 0x00B, Brick ),
  • 12, ( hexa 0x00C, Yard ),
  • 256, ( hexa 0x100, Frame ), The exFrameColorExt specifies the color to show the frame. The Frame flag can be combined with any other flags. 
  • 768, ( hexa 0x300, FrameThick ), The exFrameColorExt specifies the color to show the frame. The Frame flag can be combined with any other flags. 

(Numeric expression)

  • patterncolor, equivalent of BackgroundExtValue( Index, exPatternColorExt (8))

Indicates the color to show the pattern on the object. The exPatternColorExt property has effect only if the exPatternExt property is not 0 ( empty ). The exFrameColorExt specifies the color to show the frame ( the exPatternExt property includes the exFrame or exFrameThick flag ). Sample: "root[pattern=0x006,patterncolor=RGB(255,0,0)]"

(Color expression)

  • frame, equivalent of BackgroundExtValue( Index, exFrameColorExt (9))

Indicates the color to show the border-frame on the object. This property set the Frame flag for exPatternExt property. Sample: "root[frame=RGB(0,0,0)]"

(Color expression)

  • framethick, equivalent of BackgroundExtValue( Index, exFrameThickExt (10))

Specifies that a thick-frame is shown around the object. This property set the FrameThick flag for exPatternExt property. Sample: "root[frame=RGB(0,0,0),framethick]"

(Boolean expression)

  • data, equivalent of BackgroundExtValue( Index, exUserDataExt(11))

Specifies an extra-data associated with the object. "root[data=`any data here`]"

(Variant expression)

ALL.32:
The URL is an acronym for Uniform Resource Locator and is a reference (an address) to a resource on the Internet. For instance, let's say we need to load the picture such as: HTMLPicture("p1") = "http://www.exontrol.com/images/exontrol.png". In order to load the picture from www, you can use the GETImage property of the eXHTTP component. 

Use the GETImage method to retrieve pictures from the web. The GETImage method waits until the full picture is retrieved.  If no picture document is found at specified URL, the GETImage property fails/throw an error. Use the Timeout property to specify the amount of time (in seconds) the control will wait for the server response. Use the InField property to add additional fields to the GET request. The InField property has effect only before calling the GET method. The OutField property retrieves the header fields after GET method was performed. The OutField property has effect only after GET method was invoked. The GEM method retrieves a string if the web content is text and if it is not encoded, else a safe array of bytes is retrieved. Use the GET method to retrieve pages or documents from the web. 

The GETImage can retrieve the following type of pictures:

  • The BMP file format (*.bmp *.dib *.rle, loads the picture in BMP format), also known as bitmap image file or device independent bitmap (DIB) file format or simply a bitmap, is a raster graphics image file format used to store bitmap digital images, independently of the display device (such as a graphics adapter)
  • The JPEG file format (*.jpg *.jpe *.jpeg *.jfif, loads the picture in JPEG format, seen most often with the .jpg extension) is a commonly used method of lossy compression for digital images, particularly for those images produced by digital photography.
  • The GIF ( Graphics Interchange Format, *.gif, , loads the picture in GIF format ) is a bitmap image format that was introduced by CompuServe in 1987 and has since come into widespread usage on the World Wide Web due to its wide support and portability.
  • The TIFF (Tagged Image File Format, *.tif *.tiff, loads the picture in TIFF format) is a computer file format for storing raster graphics images, popular among graphic artists, the publishing industry, and both amateur and professional photographers in general.
  • The PNG (Portable Network Graphics, *.png, loads the picture in PNG format) is a raster graphics file format that supports lossless data compression. PNG was created as an improved, non-patented replacement for Graphics Interchange Format (GIF), and is the most used lossless image compression format on the Internet
  • The EMF ( Enhanced Metafile Format, *.emf, loads the picture in EMF format ) is a 32-bit format that can contain both vector information and bitmap information.

For instance, the Image1.Picture = http.GETImage("http://www.exontrol.com/images/exontrol.png"), assigns the picture from giving URL to Picture property of the Image Object, where the http is a global object of EXHTTPLib.HTTP type.

The following samples shows how can you load pictures using URL ( http:// ), into the eXGrid control.

VBA (MS Access, Excell...)

With Grid1
	Set http = CreateObject("Exontrol.HTTP")
	.PictureDisplay = 34
	.Picture = http.GETImage("http://www.exontrol.com/images/exontrol.png")
End With

VB6

With Grid1
	Set http = CreateObject("Exontrol.HTTP")
	.PictureDisplay = LowerRight
	.Picture = http.GETImage("http://www.exontrol.com/images/exontrol.png")
End With

VB.NET

Dim http
With Exgrid1
	' Add 'exontrol.exhttp.dll(ExHTTP.dll)' reference to your project.
	http = New exontrol.EXHTTPLib.exhttp()
	.PictureDisplay = exontrol.EXGRIDLib.PictureDisplayEnum.LowerRight
	.Picture = http.get_GETImage("http://www.exontrol.com/images/exontrol.png")
End With

VB.NET for /COM

Dim http
With AxGrid1
	http = CreateObject("Exontrol.HTTP")
	.PictureDisplay = EXGRIDLib.PictureDisplayEnum.LowerRight
	.Picture = http.GETImage("http://www.exontrol.com/images/exontrol.png")
End With

C++

/*
	Copy and paste the following directives to your header file as
	it defines the namespace 'EXGRIDLib' for the library: 'ExGrid 1.0 Control Library'

	#import <ExGrid.dll>
	using namespace EXGRIDLib;
*/
EXGRIDLib::IGridPtr spGrid1 = GetDlgItem(IDC_GRID1)->GetControlUnknown();
/*
	Includes the definition for CreateObject function like follows:

	#include <comdef.h>
	IUnknownPtr CreateObject( BSTR Object )
	{
		IUnknownPtr spResult;
		spResult.CreateInstance( Object );
		return spResult;
	};

*/
/*
	Copy and paste the following directives to your header file as
	it defines the namespace 'EXHTTPLib' for the library: 'ExHTTP 1.0 Control Library'

	#import <ExHTTP.dll>
	using namespace EXHTTPLib;
*/
EXHTTPLib::IHTTPPtr http = ::CreateObject(L"Exontrol.HTTP");
spGrid1->PutPictureDisplay(EXGRIDLib::LowerRight);
spGrid1->PutPicture(IPictureDispPtr(((ObjectPtr)(http->GetGETImage(L"http://www.exontrol.com/images/exontrol.png")))));

C++ Builder

/*
	Select the Component\Import Component...\Import a Type Library,
	to import the following Type Library:

		ExHTTP 1.0 Control Library

	TypeLib: ExHTTP.dll

	to define the namespace: Exhttplib_tlb
*/
//#include "EXHTTPLIB_TLB.h"
Exhttplib_tlb::IHTTPPtr http = Variant::CreateObject(L"Exontrol.HTTP");
Grid1->PictureDisplay = Exgridlib_tlb::PictureDisplayEnum::LowerRight;
Grid1->Picture = (IPictureDisp*)(http->get_GETImage(L"http://www.exontrol.com/images/exontrol.png"));

C#

// Add 'exontrol.exhttp.dll(ExHTTP.dll)' reference to your project.
// Add 'ExHTTP 1.0 Control Library(ExHTTP.dll)' reference to your project.
exontrol.EXHTTPLib.exhttp http = new exontrol.EXHTTPLib.exhttp();
exgrid1.PictureDisplay = exontrol.EXGRIDLib.PictureDisplayEnum.LowerRight;
exgrid1.Picture = (http.get_GETImage("http://www.exontrol.com/images/exontrol.png") as Object);

JS/JavaScript

<BODY onload="Init()">
<OBJECT CLASSID="clsid:101EE60F-7B07-48B0-A13A-F32BAE7DA165" id="Grid1"></OBJECT>

<SCRIPT LANGUAGE="JScript">
function Init()
{
	var http = new ActiveXObject("Exontrol.HTTP");
	Grid1.PictureDisplay = 34;
	Grid1.Picture = http.GETImage("http://www.exontrol.com/images/exontrol.png");
}
</SCRIPT>
</BODY>

VBScript

<BODY onload="Init()">
<OBJECT CLASSID="clsid:101EE60F-7B07-48B0-A13A-F32BAE7DA165" id="Grid1"></OBJECT>

<SCRIPT LANGUAGE="VBScript">
Function Init()
	With Grid1
		Set http = CreateObject("Exontrol.HTTP")
		.PictureDisplay = 34
		.Picture = http.GETImage("http://www.exontrol.com/images/exontrol.png")
	End With
End Function
</SCRIPT>
</BODY>

C# for /COM

// Add 'ExHTTP 1.0 Control Library(ExHTTP.dll)' reference to your project.
EXHTTPLib.HTTP http = new EXHTTPLib.HTTP();
axGrid1.PictureDisplay = EXGRIDLib.PictureDisplayEnum.LowerRight;
(axGrid1.GetOcx() as EXGRIDLib.Grid).Picture = (http.get_GETImage("http://www.exontrol.com/images/exontrol.png") as Object);

X++ (Dynamics Ax 2009)

public void init()
{
	anytype http;
	;

	super();

	// Add 'exhttp.dll(ExHTTP.dll)' reference to your project.
	// Add 'ExHTTP 1.0 Control Library(ExHTTP.dll)' reference to your project.
	http = COM::createFromObject(new EXHTTPLib.exhttp()); http = http;
	exgrid1.PictureDisplay(34/*LowerRight*/);
	exgrid1.Picture(http.GETImage("http://www.exontrol.com/images/exontrol.png"));
}

Delphi 8 (.NET only)

with AxGrid1 do
begin
	http := (ComObj.CreateComObject(ComObj.ProgIDToClassID('Exontrol.HTTP')) as EXHTTPLib.HTTP);
	PictureDisplay := EXGRIDLib.PictureDisplayEnum.LowerRight;
	(GetOcx() as EXGRIDLib.Grid).Picture := (http.GETImage['http://www.exontrol.com/images/exontrol.png'] as Object);
end

Delphi (standard)

with Grid1 do
begin
	http := (IUnknown(ComObj.CreateComObject(ComObj.ProgIDToClassID('Exontrol.HTTP'))) as EXHTTPLib_TLB.HTTP);
	PictureDisplay := EXGRIDLib_TLB.LowerRight;
	Picture := (IUnknown(http.GETImage['http://www.exontrol.com/images/exontrol.png']) as _TLB.Object);
end

VFP

with thisform.Grid1
	http = CreateObject("Exontrol.HTTP")
	.PictureDisplay = 34
	.Picture = http.GETImage("http://www.exontrol.com/images/exontrol.png")
endwith

dBASE Plus

local http,oGrid

oGrid = form.EXGRIDACTIVEXCONTROL1.nativeObject
http = new OleAutoClient("Exontrol.HTTP")
oGrid.PictureDisplay = 34
oGrid.Picture = http.GETImage("http://www.exontrol.com/images/exontrol.png")

XBasic (Alpha Five)

Dim http as P
Dim oGrid as P

oGrid = topparent:CONTROL_ACTIVEX1.activex
http = OLE.Create("Exontrol.HTTP")
oGrid.PictureDisplay = 34
oGrid.Picture = http.GETImage("http://www.exontrol.com/images/exontrol.png")

Visual Objects

local http as IHTTP

// Generate Source for 'ExHTTP 1.0 Control Library(ExHTTP.dll)' server from Tools\Automation Server...
http := IHTTP{"Exontrol.HTTP"}
oDCOCX_Exontrol1:PictureDisplay := LowerRight
oDCOCX_Exontrol1:Picture := http:[GETImage,"http://www.exontrol.com/images/exontrol.png"]

PowerBuilder

OleObject http,oGrid

oGrid = ole_1.Object
http = CREATE OLEObject
http.ConnectToNewObject("Exontrol.HTTP")
oGrid.PictureDisplay = 34
oGrid.Picture = http.GETImage("http://www.exontrol.com/images/exontrol.png")

Visual DataFlex

Procedure OnCreate
	Forward Send OnCreate
	Variant http
	Get Comcreateobject "Exontrol.HTTP" to http
	Set ComPictureDisplay to OLELowerRight
	Set ComPicture to http
End_Procedure

XBase++

#include "AppEvent.ch"
#include "ActiveX.ch"

PROCEDURE Main
 	LOCAL oForm
	LOCAL nEvent := 0, mp1 := NIL, mp2 := NIL, oXbp := NIL
	LOCAL oGrid
	LOCAL http

	oForm := XbpDialog():new( AppDesktop() )
	oForm:drawingArea:clipChildren := .T.
	oForm:create( ,,{100,100}, {640,480},, .F. )
	oForm:close  := {|| PostAppEvent( xbeP_Quit )}

	oGrid := XbpActiveXControl():new( oForm:drawingArea )
	oGrid:CLSID  := "Exontrol.Grid.1" /*{101EE60F-7B07-48B0-A13A-F32BAE7DA165}*/
	oGrid:create(,, {10,60},{610,370} )

		http := CreateObject("Exontrol.HTTP")
		oGrid:PictureDisplay := 34/*LowerRight*/
		oGrid:Picture := http:GETImage("http://www.exontrol.com/images/exontrol.png")

	oForm:Show()
	DO WHILE nEvent != xbeP_Quit
		nEvent := AppEvent( @mp1, @mp2, @oXbp )
		oXbp:handleEvent( nEvent, mp1, mp2 )
	ENDDO 
RETURN
ALL.33:
Most of our components provides a Layout property that helps you to store/restore the control's layout. For instance, you can save the control's Layout property to a file when the application is closing, and you can restore the control's layout when the application is loaded. The Layout property saves almost all of the control's properties that user can change at runtime ( like changing the column's position by drag and drop ). The Layout property does NOT save the control's data, so the Layout property should be called once you loaded the data from your database, xml or any other alternative. Once the data is loaded, you can call the Layout property to restore the View as it was saved. Before closing the application, you can call the Layout property and save the content to a file for reading next time the application is opened. Here's a movie on how the Layout works. 

Usually, the Layout property looks such as: "gAxAAyAECgkGgsDhMHhQAAEB...."

Let's take the Layout property of the eXGrid component. The Layout property saves/loads the following information:

  • columns size and position
  • current selection
  • scrolling position and size
  • expanded/collapsed items, if any
  • sorting columns
  • filtering options
  • SearchColumnIndex/FocusColumnIndex property, indicates the focusing column, or the column where the user can use the control's incremental searching.
  • TreeColumnIndex property, which indicates the index of the column that displays the hierarchy lines.

The Layout property saves these properties in BASE64 format ( compressed ). In order to decompose the BASE64 string, you need to use the Decode64TextW property of the eXPrint component.

Here's what you need to do in order to view/decode the Layout's content:

  • Insert the eXPrint component in the same form/dialog/window where the eXGrid is hosted
  • Call the Decode64TextW property like in the following sample:
    With Print1
        Debug.Print (.Decode64TextW(Grid1.Object.Layout))
    End With

If using the /COM version of the component you can directly view/decode the Layout property using the following:

Debug.Print (Grid1.ExecuteTemplate("CreateObject(`Exontrol.Print`).Decode64TextW(Me.Layout)"))

Once you call the code you should get something like follows

c0.filter="Child 1"
c0.filtertype=240
c0.position=0
c0.select=0
c0.visible=1
c0.width=113
c1.filtertype=0
c1.position=2
c1.select=0
c1.visible=1
c1.width=36
c2.filtertype=0
c2.position=3
c2.select=0
c2.visible=1
c2.width=36
c3.filtertype=0
c3.position=4
c3.select=0
c3.visible=1
c3.width=36
c4.filtertype=0
c4.position=1
c4.select=0
c4.visible=1
c4.width=64
collapse="0 5"
columns=5
focus=16
focuscolumnindex=0
hasfilter=1
hscroll=0
multiplesort="C2:1 C1:2"
searchcolumnindex=1
select="11 16"
selectcolumnindex=0
treecolumnindex=0
vscroll=0
vscrolloffset=0

The content of the Layout is composed by a set of properties, separated ; or \r\n characters. Each property is composed by a field and a value separated by a = character. If a field supports multiple values, they are included between " characters ( the same as a field of string type ), and separated by space character. For instance, "0 2-4" indicates the value 0, 2, 3 and 4. The value for fields of date type are represented in the #MM/DD/YYYY# format.

The known fields/properties are:

  • hscroll=value, indicates the horizontal scroll position (value). The value is a number.
  • vscroll=value, indicates the vertical scroll position (value). The value is a number.
  • searchcolumnindex=value, specifies the index of the column where incremental search occurs. The value is a number.
  • treecolumnindex=value, specifies the index of the column that displays the hierarchy/tree. The value is a number. Sample: treecolumnindex=-1, and so no column will display the hierarchy/tree
  • selectcolumnindex=value, specifies the index of the selected column. The value is a number.
  • focuscolumnindex=value, specifies the index of the focused column. The value is a number, and it is valid for controls that has built-in editors. 
  • vscrolloffset=value, specifies the vertical offset to show the first visible item. The value is a number.
  • chart.firstvisibledate=value, specifies the first visible date to be shown on the control's chart. The value is a date, and the field is valid for gantt related controls. Sample: chart.firstvisibledate=#06/21/2005#
  • chart.rightpanewidth=value, indicates the width in pixels of the right panel of the control (chart panel). The value is a numeric, and the field is valid for gantt-related controls.
  • chart.hscroll=value, indicates the horizontal scroll position, in the chart panel of the control (value). The value is a number, and the field is valid for gantt-related controls.
  • hasfilter=value, indicates if the layout applies any filter on the control. The value is a number.
  • filterprompt=value, specifies caption of the filter-prompt feature. The value is a string. The field is valid for controls the support FilterPrompt feature.
  • select=value, specifies the list of selected items. The value is a string that contains numbers, separated by space character, each number indicates an index to an item. Sample: select="1", selects the item with the index 1, or select="0 2-4", selects the items with the index 0, 2, 3 and 4.
  • focus=value, specifies the index of the item being focused. The value is a number. Sample: focus=1, focuses the item with the index 1.
  • collapse=value, specifies the list of collapsed items. The value is a string that contains numbers, separated by space character, each number indicates an index to an item. Sample: collapse="1", collapses the item with the index 1, or collapse="0 2-4", collapses the items with the index 0, 2, 3 and 4.
  • multiplesort=value, specifies the list of sorted columns as they are displayed in the control's sort bar. The value is a string, that specifies the list of c<index>:sortorder elements separated by space character. The c<index> is an identifier like C0, C1, ..., where the sortorder could be 1 for ascending, and 2 for descending. The field has effect if the control supports multiple-sort. Sample: multiplesort="C0:2 C1:1" sorts descending the column with the index 0, and ascending the column with the index 1.
  • singlesort=value, specifies the sorted column. The value is a string, that specifies c<index>:sortorder element. The c<index> is an identifier like C0, C1, ..., where the sortorder could be 1 for ascending, and 2 for descending. The field has effect if the control supports multiple-sort. Sample: singlesort="C1:2" sorts descending the column with the index 1.
  • columns=value, specifies the number of columns. The value is a number, that specifies the number of columns. If the columns field is missing or 0, any field related to columns is ignored.
  • c<index>.position=value, specifies the position of the column with the giving <index>. The value and <index> are numeric, starting from 0. Sample: "columns=1;c0.position = 2", change the position of the column with the index 0 to be 2.
  • c<index>.visible=value, specifies whether the column with the giving <index> is visible or hidden. The value and <index> are numeric. 0 indicates hidden, else visible. Sample: "columns=1;c0.visible = 0", hides the column with the index 0. 
  • c<index>.width=value, indicates width in pixels, of the column with the giving <index>. The value and <index> are numeric. 
  • c<index>.select=value, specifies whether the column with the giving <index> is selected or un-selected. The value and <index> are numeric. 0 indicates not-selected, else selected. Sample: "columns=1;c0.select = 1", selects the column with the index 0. The field is valid whether the control supports rectangular-selection.
  • c<index>.formatlevel=value, specifies the format of the column with the giving <index>. The <index> is numeric, while the value is string. For instance, the "columns=3;c0.formatlevel = ""1/2"";c1.visible=0;c2.visible=0", hides the column with the index 1 and 2, and makes the column with the index 0 to display columns one bellow other. The field is valid if the control supports FormatLevel feature.
  • c<index>.cellformatlevel=value, specifies the format of the cells within the column with the giving <index>. The <index> is numeric, while the value is string. For instance, the "columns=3;c0.cellformatlevel = ""1/2"";c1.visible=0;c2.visible=0", hides the column with the index 1 and 2, and makes the cells of the column with the index 0 to display cells one bellow other. The field is valid if the control supports FormatLevel feature. 
  • c<index>.filter=value, specifies the filter to be applied on the column with the giving <index>. The <index> is numeric, while the value is string. The field is valid for controls that supports filtering. The filter field is equivalent with the Column.Filter property.
  • c<index>.filtertype=value, specifies the type of the filter to be applied on the column with the giving <index>. The <index> is numeric, while the value is numeric. The field is valid for controls that supports filtering. The filtertype field is equivalent with the Column.FilterType property.
  • c<index>.key=value, specifies the key of the column with the giving <index>. The <index> is numeric, while the value is string. The key field is equivalent with the Column.Key property.

For instance, 

  • c4.width=64 indicates that the width of the column with the index 4 ( 0-based ), has the width of 64-pixels wide. 
  • collapse="0 5" indicates that the items 0 and 5 are collapsed.
  • multiplesort="C2:1 C1:2", sorts multiple-columns as follow: sorts ascending the column with the index 2, and sorts descending the column with the index 1.

The decoded Layout string, can be changed, updated or modified, and the new value can be set to the Layout property, so you can ignore / prevent certain actions to happen or be loaded by the Layout property. You can add multiple fields to Layout property separated by ; or \r\n characters.

For instance, 

  • Grid1.Object.Layout = ""focus=1", focuses the item with the index 1 ( second item, by adding )
  • Grid1.Object.Layout = ""collapse=""0-99""", collapses the items between 0 and 99 ( inclusive), while the other are expanded. If the list contains less items, the property affect only existing items.
  • Grid1.Object.Layout = ""collapse=""""", expands all items.
  • Grid1.Object.Layout = "multiplesort="""";singlesort=""""", removes any previously sorting
  • Grid1.Object.Layout = "multiplesort=""C3:1""", sorts ascending the column with the index 3 ( and add it to the sort bar if visible )
  • Grid1.Object.Layout = "multiplesort=""C2:1 C1:2""" removes any previously sorting, and sort-multiple as indicated by the multiplesort field.
  • Grid1.Object.Layout = "singlesort=""C4:2""", sorts descending the column with the index 4 ( it is not added to sort bar panel )
  • Grid1.Object.Layout = "multiplesort=""C3:1"";singlesort=""C4:2""", sorts ascending the column with the index 3 ( and add it to the sort bar if visible ), and sorts descending the column with the index 4. In other words, it re-sort the control by columns 3 and 4.
  • Grid1.Object.Layout = "multiplesort=""C3:1 C5:2"";singlesort=""C4:2""", sorts ascending the column with the index 3 ( and add it to the sort bar if visible ), sorts descending the column with the index 5 ( and add it to the sort bar if visible ), and sorts descending the column with the index 4. In other words, it re-sort the control by columns 3, 5 and 4.

The double-quote characters inside the string indicate single-quote quote, such as "" is translated to ". For instance, the string "multiplesort="""";singlesort=""""", indicates the value of: multiplesort="";singlesort="". In C++, this should be translated as: "multiplesort=\"\";singlesort=\"\""

ALL.34:
Writing a DPI?aware application is the key to making a UI look consistently good across a wide variety of high-DPI display settings. Applications that are not DPI?aware but are running on a high-DPI display setting can suffer from many visual artifacts, including incorrect scaling of UI elements, clipped text, and blurry images. By adding support in your application for DPI awareness, you ensure that the presentation of your application's UI is more predictable, making it more visually appealing to users. This gives the user the best possible experience on any display. Even if the DPI is available starting from Windows XP, the DPI-Aware support for our components has been added recently, so definitely, older versions does not have DPI-Aware support. By default, the windows application are DPI-unware, excepts the /WPF applications.

The application determines the level of the DPI-awareness, based on the dpiAware value in its manifest.

  • The following manifest shows how you can specify your application to be DPI-Aware:
    <?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
    <assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
      <asmv3:application>
        <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
          <dpiAware>True</dpiAware>
        </asmv3:windowsSettings>
      </asmv3:application>
    </assembly>
  • If using the component in Microsoft Office Suite, like Excel, Access, or Word, starting from 2013 the version of Microsoft Office is a DPI-Aware application
  • A /WPF application, is a DPI-Aware application

Setting DPI Using Control Panel. The following screen shot shows the Display setting of your Control Panel, where you can change the DPI settings:

The following screen shots show exgrid component with / without DPI-Aware support (older), on DPI-Aware / DPI-Unaware applications.

  • exgrid, with DPI-Scale of 100%:

  • A) exgrid with DPI-Aware support, on a DPI-Aware application, with DPI-Scale of 175%:
  • B) exgrid with no DPI-Aware support (older), on a DPI-Aware application, with DPI-Scale of 175%:
  • C) exgrid with/without DPI-Aware support (any), on a DPI-Unaware application, with DPI-Scale of 175%:

The DPI-Aware Support of the Component adds the following changes:

  • all of the non-resizable UI elements of the component are scaled proportionally to the DPI settings, as glyphs, icons, pictures, buttons, check-boxes, radio-buttons and so on.
  • the Handle parameter of Images method can be a string that specifies the ICO file to be loaded. The ICO file format is an image file format for computer icons in Microsoft Windows. ICO files contain one or more small images at multiple sizes and color depths, such that they may be scaled appropriately. For instance, Images("e:\working\sync.ico") method adds the sync.ico file to the control's Images collection.
  • the exClientExt attribute of the EBN/BackgroundExt/BackgroundExtValue supports DPI values, if the number is followed by a D character. For instance, if the DPI scaling is 100%, the 16d is 16, while for a 150% DPI scaling, the 16d is 24. In other words, "top[4,back=RGB(0,0,255)]", draws a blue line on the top side of the object's background, of 4-pixels wide, no matter of DPI scaling, while "top[4D,back=RGB(0,0,255)]", draws the line of 4-pixels wide if DPI scaling is 100%, or 6-pixels wide if DPI scaling is 150% )
  • the coordinates of the CP clause of the Skin parameter of VisualAppearance.Add method can be followed by a D character, which indicates the value according to the current DPI settings. For instance, "CP:1 -2 -2 2 2", copies the EBN with the identifier 1, and displays it on a 2-pixels wider rectangle no matter of the DPI settings, while "CP:1 -2D -2D 2D 2D" displays it on a 2-pixels wider rectangle if DPI settings is 100%, and on on a 3-pixels wider rectangle if DPI settings is 150%.
  • the expression properties support `dpi`, `dpix` and `dpiy` constants that returns the current DPI setting on x/y scale. For instance, the "value * dpi" returns the value if the DPI setting is 100%, or value * 1.5 in case, the DPI setting is 150%
ALL.35:
Properties or Parameters of Variant type can hold anything, from numbers, strings to objects, including a reference to number, string and objects.

A) The problem may occur once you store the reference to an object to such of property, and later the object is closed, and so not accessible anymore, and so your property won't function properly.

Shortly, having the rs variable as a a reference to a Recordset ( ADO or DAO ) object, the rs("field") or rs(index) returns a reference to a Field object rather than field's value, so any of the following statements won't work correctly.

For instance:

  • Items.AddItem rs(0) adds a new item
  • Items.CellValue(...) = rs(0) changes the cell's value
  • Items.AddBar ..., rs(0), adds a new bar with specified key
  • Items.ItemBar(...) = rs(0), changes a property of the giving bar

 so, the correct way to store the Field's value is:

  • Items.AddItem rs(0).Value
  • Items.CellValue(...) =  rs(0).Value
  • Items.AddBar ...,  rs(0).Value,
  • Items.ItemBar(...) =  rs(0).Value,

or

  • Items.AddItem CStr(rs(0))
  • Items.CellValue(...) =  CStr(rs(0))
  • Items.AddBar ...,  CStr(rs(0)),
  • Items.ItemBar(...) =  CStr(rs(0)),

The Value property of the Field object returns the field's value, or CStr function gets a COPY of the field's value, rather that the field's reference. 

B) Another problem may occur once you store the reference to a member, which is declared local, and referred later in another context, where it is not valid anymore.

For instance:

  • Dim sLinkKey As String
    sLinkKey = "L1"
    Items.AddLink
    sLinkKey, ...

This code may function different in VB6 and MS Access. In VB6 the value of sLinkKey is passed by value, while in MS Access is passed by reference. In order to prevent passing the value by reference, you need to use a conversion function like explained earlier, so the code can shows as:

  • Dim sLinkKey As String
    sLinkKey = "L1"
    Items.AddLink CStr(sLinkKey), ...

Certainly, you can use any of conversion functions such as:

  • CStr
  • CDbl
  • CDate
  • CInt
  • and so on 
ALL.36:
ALL.37:

The AttachTemplate/x-script code is a simple way of calling control/object's properties, methods/events using strings. The AttachTemplate features allows you to attach a x-script code to the component. The AttachTemplate method executes x-script code ( including events ), from a string, file or a safe array of bytes. This feature allows you to run any x-script code for any configuration of the component /COM, /NET or /WPF. Exontrol owns the x-script implementation in its easiest form and it does not require any VB engine or whatever to get executed. The x-script code can be converted to several programming languages using the eXHelper tool.

The following movies shows how you can use the AttachTemplate feature:

The following sample opens the Windows Internet Explorer once the user clicks the control ( /COM version ):

Gauge1.AttachTemplate "handle Click(){ CreateObject(`internetexplorer.application`){ Visible = True; Navigate(`http://www.exontrol.com`) } } "

The following x-script code opens the Windows Internet Explorer once the user clicks the control ( /COM version ):

handle Click()
{
	CreateObject("internetexplorer.application")
	{
		Visible = True
		Navigate("http://www.exontrol.com")
	}
}

This x-script is equivalent with the following VB code:

Private Sub Gauge1_Click()
    With Control
        With CreateObject("internetexplorer.application")
            .Visible = True
            .Navigate ("http://www.exontrol.com")
        End With
    End With
End Sub

The following sample opens the Windows Internet Explorer once the user clicks the control ( /NET or /WPF version ):

Exgauge1.AttachTemplate("handle Click() { CreateObject(`System.Diagnostics.Process, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`) { Dim p; p = CreateObject(`System.Diagnostics.ProcessStartInfo, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`) { FileName = `IExplore.exe`; Arguments = `http://www.exontrol.com/` } StartInfo = p; Start } } ")

The following x-script code opens the Windows Internet Explorer once the user clicks the control ( /NET or /WPF version ):

handle Click()
{
	CreateObject("System.Diagnostics.Process, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
	{
		Dim p
		p = CreateObject("System.Diagnostics.ProcessStartInfo, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
		{
			FileName = "IExplore.exe"
			Arguments = "http://www.exontrol.com/"
		}
		StartInfo = p
		Start
	}
}

This x-script is equivalent with the following VB/NET code:

Private Sub Exgauge1_Click(ByVal sender As System.Object) Handles Exgauge1.Click
    With New System.Diagnostics.Process()
        Dim p As System.Diagnostics.ProcessStartInfo = New System.Diagnostics.ProcessStartInfo()
        With p
            .FileName = "IExplore.exe"
            .Arguments = "http://www.exontrol.com/"
        End With
        .StartInfo = p
        .Start()
    End With
End Sub

The AttachTemplate/x-script syntax in BNF notation is defined like follows:

<x-script> := <lines>
<lines> := <line>[<eol> <lines>] | <block>
<block> := <call> [<eol>] { [<eol>] <lines> [<eol>] } [<eol>]
<eol> := ";" | "\r\n"
<line> := <dim> | <createobject> | <call> | <set> | <comment> | <handle>[<eol>]{[<eol>]<lines>[<eol>]}[<eol>]
<dim> := "DIM" <variables>
<variables> := <variable> [, <variables>]
<variable> := "ME" | <identifier>
<createobject> := "CREATEOBJECT(`"<type>"`)"
<call> := <variable> | <property> | <variable>"."<property> | <createobject>"."<property>
<property> := [<property>"."]<identifier>["("<parameters>")"]
<set> := <call> "=" <value>
<property> := <identifier> | <identifier>"("[<parameters>]")"
<parameters> := <value> [","<parameters>]
<value> := <boolean> | <number> | <color> | <date> | <string> | <createobject> | <call>
<boolean> := "TRUE" | "FALSE"
<number> := "0X"<hexa> | ["-"]<integer>["."<integer>]
<digit10> := 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9
<digit16> := <digit10> | A | B | C | D | E | F
<integer> := <digit10>[<integer>]
<hexa> := <digit16>[<hexa>]
<color> := "RGB("<integer>","<integer>","<integer>")"
<date> := "#"<integer>"/"<integer>"/"<integer>" "[<integer>":"<integer>":"<integer>"]"#"
<string> := '"'<text>'"' | "`"<text>"`"
<comment> := "'"<text>
<handle> := "handle " <event>
<event> := <identifier>"("[<eparameters>]")"
<eparameters> := <eparameter> [","<eparameters>]
<parameters> := <identifier>

where:

<identifier> indicates an identifier of the variable, property, method or event, and should start with a letter.
<type> indicates the type the CreateObject function creates, as a progID for /COM version or the assembly-qualified name of the type to create for /NET or /WPF version
<text> any string of characters

The Template or x-script is composed by lines of instructions. Instructions are separated by "\n\r" ( newline characters ) or ";" character.

An x-script instruction/line can be one of the following:

  • Dim variable[, variable, ...] declares the variables in the context. Multiple variables are separated by commas. ( Sample: Dim h, h1, h2 )
  • variable = [object.][property/method( arguments ).]property/method( arguments ) assigns the result of the property/method call to the variable.  ( Sample: h = InsertItem(0,"New Child") )
  • [object.][property/method( arguments ).]property( arguments ) = value assigns the value to the property. ( Sample: Columns.Add(`Hidden`).Visible = False )
  • [object.][property/method( arguments ).]property/method( arguments ) invokes the property/method. ( Sample: Columns.Add(`Column`) )
  • {context } delimits the object's context. The properties/fields or methods called between { and } are related to the last object returned by the property/method prior to { declaration. (Sample: Nodes{Add(`Child 1`);Add(`Child 2`)} )
  • . delimits the object than its property or method. (Sample: Nodes.Add(`Element`), or Nodes.Add(`Element`) and Nodes{Add(`Element`)} are equivalents )

where

  • variable is the name of a variable declared with Dim command or previously defined using the TemplateDef method.
  • property is the name of a property/field of the current object in the current context.
  • method is the name of a method of the current object in the current context.
  • arguments include constants and/or variables and/or property/method calls separated by comma character.
  • object can be a variable of an Object type, Me or CreateObject call.

The x-script may uses constant expressions as follow:

  • boolean expression with possible values as True or False. The True value is equivalent with -1, while False with 0. (Sample: Visible = False )
  • numeric expression may starts with 0x which indicates a hexa decimal representation, else it should starts with digit, or +/- followed by a digit, and . is the decimal separator. Sample: 13 indicates the integer 13, or 12.45 indicates the double expression 12,45 ( Sample: BackColor = 0xFF0000 ) 
  • date expression is delimited by # character in the format #mm/dd/yyyy hh:mm:ss#. For instance, #31/12/1971# indicates the December 31, 1971 ( Sample: Chart.FirstVisibleDate = #1/1/2001# )
  • string expression is delimited by " or ` characters. If using the ` character, please make sure that it is different than ' which allows adding comments inline. Sample: "text" or `text` indicates the string text, while the ' text , specifies the comment text ( Sample: Columns.Add(`Column`).HTMLCaption = "<b>caption</b>" )

Also , the template or x-script code may support general functions as follows:

  • Me property indicates the original object, and it is defined as a predefined variable.  ( Sample: Me.Nodes.Add(`Element`) )
  • RGB(R,G,B) property retrieves an RGB value, where the R, G, B are byte values that indicates the Red Green Blue bytes for the color being specified. ( Sample: Nodes.Add(`Root 1`).BackColor = RGB(255,0,0) )
  • LoadPicture(file) property loads a picture from a file and returns a Picture object required by the picture properties. (Sample: Picture = LoadPicture(`C:\exontrol\images\auction.gif`)
  • Print(string) method sends a string to the debugger for display. ( Sample: Print(`Element`) )
  • CreateObject(progID) property creates and retrieves a single uninitialized object of the class associated with a specified program identifier ( progID for /COM ) or the assembly-qualified name of the type to create for /NET or /WPF version ( Sample: CreateObject(`ADODB.Recordset`), creates an ADO Recordset for /COM version, CreateObject(`System.Diagnostics.ProcessStartInfo, System, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089`), create a System.Diagnostics.ProcessStartInfo object using the /NET or /WPF version )
ALL.38:
When your application runs under DPI scale, the size of text or items appear larger or smaller. A higher DPI level has everything appear larger, and a lower DPI level has everything appear smaller. The default DPI level is 100% (96 DPI). In order to ensure that your application is DPI-aware, please check here.

For instance, the /WPF framework provides the property ActualWidth that gets the rendered width of the element. The eXG2antt/WPF's Chart.PaneWidthLeft and Chart.PaneWidthRight properties returns the width of left and right panels of the control. Theoretically, the Chart.PaneWidthLeft + Chart.PaneWidthRight gives the width of the control, but this value is not compatible with what ActualWidth returns (compatible only if DPI scale is 100%). In order to make them equivalent, the ActualWidth should be multiplied by DPI factor, or Chart.PaneWidthLeft / Chart.PaneWidthRight should be divided by DPI factor like in the following samples:

Debug.Print(Exg2antt1.FormatABC("round(C - (A+B)/dpi)", Exg2antt1.Chart.PaneWidthLeft, Exg2antt1.Chart.PaneWidthRight, Exg2antt1.ActualWidth))
Debug.Print(Exg2antt1.FormatABC("round(C*dpi - (A+B))", Exg2antt1.Chart.PaneWidthLeft, Exg2antt1.Chart.PaneWidthRight, Exg2antt1.ActualWidth))

Both lines use the FormatABC method that supports the dpi predefined-constant that specifies the current DPI setting, it indicates the minimum value between dpix and dpiy constants. For instance, if current DPI setting is 100%, the dpi constant returns 1, if 150% it returns 1.5, and so on. Shortly, the code is translated as:

Exg2antt1.ActualWidth == (Exg2antt1.Chart.PaneWidthLeft + Exg2antt1.Chart.PaneWidthRight) / dpi
or
Exg2antt1.ActualWidth * dpi == (Exg2antt1.Chart.PaneWidthLeft + Exg2antt1.Chart.PaneWidthRight)
Any of Chart.PaneWidthLeft / Chart.PaneWidthRight property does not include the width of the control's vertical-scroll bar. In conclusion, when you require DPI-values for size of visual-elements, you need to use the dpi constant, and the value of the size-property (Width, UnitWidth, Height, ItemHeight, and so on)
ALL.39:

A manifest is a XML file that contains settings that informs Windows how to handle a program when it starts. The manifest can be embedded inside the program file (as a resource under 24\1) or it can be located in a separate external XML file. If the manifest is placed in a separate file, then the file must be located in the same folder as the executable file and it must have same filename as the program file, but with a ".manifest" filename extension added at the end (e.g "MYAPP.EXE.manifest").

You can provide a manifest for your application, by including the manifest file to the application's resource under 24( Manifest Resource Type ) with the identifier 1. The following steps show how you can define your application as DPI-Aware (or how to add the manifest-file as a resource), using the following manifest:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?> 
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3" >
  <asmv3:application>
    <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
      <dpiAware>True</dpiAware>
    </asmv3:windowsSettings>
  </asmv3:application>
</assembly>
For instance, the dpiAware setting can make the difference between the following:

compared with

(this is the eXFolderView component running on an application without DPI-aware setting, and with DPI-aware)

This article shows how you can:

  1. Add the manifest using Visual Studio (applicable to any executable)
  2. Add the manifest using "Project\Add New Resource File" of Visual Basic 6/VB6 (applicable to VB6 executable only)

1. Add the manifest using Visual Studio (applicable to any executable).

Open the Visual Studio, and follow the steps:
  • Select the MYAPP.EXE file, as resource using the File\Open\File..., so you can see the resources as:
  • Right click the Myapp.exe to select Add Resource...
  • Add Custom Resource of 24 typeas:
  • Paste the manifest-file into the RCDATA as:
  • Rename the 101 identifier to 1, as:
Now, the MYAPP.EXE file contains a manifest file. Run the application, and if no errors occur it means that the manifest file is OK, else a message box like follows:

could be displayed.

See also:

2. Add the manifest using "Project\Add New Resource File" of VB6 (applicable to VB6 executable only).

  • Generating the RES file:
    • Open Visual Studio, select File\New\File and choose: Native Resource Template
    • Right-click the .rct iem and select the Add Resource ...
    • Add Resource dialog is opened, select Custom, and type 24, click OK
    • Paste the manifest-content to the Custom resource you created (CTRL + V)
    • Click Properties, to you change the identifier of the resource item from IDR_RT_MANIFEST1 to 1
    • Save the template, by pressing the CTRL + S, so the Save File As dialog is opened
    • Select the 32-bit Resource File (*.res), from Save as type field
    • Change the name and location where the RES file to be saved ( for instance, MYAPP.res ), so it points to your VB6 project folder
    • Click the Save button
    • Finally, you have generated the RES file that includes the Resource Type 24/Manifest with the identifier 1, which contains the manifest file
  • Include the RES file as resource to your project
    • Open the VB6 project,
    • Go to Add-Ins\Add-In Manager...
    • Load the VB6 Resource Editor ( Load Behavior Check )
    • Go to Project \ Add New Resource File ...
    • The Open A Resource File dialog is opened
    • Select the RES file you previously generated ( MYAPP.res )
    • Click Open, and so the Project will show a new item MYAPP.res under the Related Documents
  • Generate the EXE file
    • Select the File \ Make Project1.exe ...
    • Change the name of the EXE to MYAPP.exe and click OK
    •  Save all, and close the VB6 project
Now, the MYAPP.EXE file contains a manifest file. Run the application, and the most probabily you will get the following error:

So, please check also:

You can download here the VB sample. Register or install the ExFolderView.dll, and run the MYAPP.exe and DPI-Aware\MYAPP.exe, and you shoudl see the differences.
ALL.40:

Almost all of our controls provide the following methods:

  • Images method, loads one or more icons from different type of sources (ICO-file, BASE64 encoded image list, ImageList controls, Picture objects, and so on)
  • ReplaceIcon method, adds a new icon, replaces an icon or clears the control's image list. For instance the ReplaceIcon 0, -1 clears the control's Images collection 

to load icons at runtime.

The Handle parameter of the Images method supports any of the following:

  • A string expression that specifies the ICO file to add. The ICO file format is an image file format for computer icons in Microsoft Windows. ICO files contain one or more small images at multiple sizes and color depths, such that they may be scaled appropriately. For instance, Images("c:\temp\copy.ico") method adds the sync.ico file to the control's Images collection
  • A string expression that indicates the BASE64 encoded string that holds the icons to add. You must use the ExImages tool to save/load your icons as BASE64 encoded format. In this case the string may begin with "gBJJ..."
  • A reference to a Microsoft ImageList control (mscomctl.ocx, MSComctlLib.ImageList type) that holds the icons to add
  • A reference to a Picture (IPictureDisp implementation) that holds the icon to add. For instance, the VB's LoadPicture (Function LoadPicture([FileName], [Size], [ColorDepth], [X], [Y]) As IPictureDisp) or LoadResPicture (Function LoadResPicture(id, restype As Integer) As IPictureDisp) returns a picture object.
  • A long expression that identifies a handle to an Image List Control ( the Handle should be of HIMAGELIST type ). On 64-bit platforms, the Handle parameter must be a Variant of LongLong / LONG_PTR data type ( signed 64-bit (8-byte) integers ), saved under llVal field, as VT_I8 type. The LONGLONG / LONG_PTR is __int64, a 64-bit integer. For instance, in C++ you can use as Images( COleVariant( (LONG_PTR)hImageList) ) or Images( COleVariant( (LONGLONG)hImageList) ), where hImageList is of HIMAGELIST type. The GetSafeHandle() method of the CImageList gets the HIMAGELIST handle.

The following VB samples show how you can use the Images method:

  • loads the icon using its path
    control.Images "C:\Temp\copy.ico"
  • loads the icon using its path (VB's LoadPicture method)
    control.Images LoadPicture("C:\Temp\copy.ico")
  • loads the icon using the ReplaceIcon method:
    control.ReplaceIcon LoadPicture("C:\Temp\copy.ico")
  • loads the icon from the resource (VB's LoadResPicture method)
    control.Images LoadResPicture(101, vbResIcon)
  • loads icons using base64 encoded string (ExImages tool)
    Dim s As String
    s = "gBJJgBggAAQAAgACkKAD/hz/EMNh8TIRNGwAjEZAEXjAojJQjMLjABAAgjUYDMnlUrgktl0vmExAIMmgajIxjIznM7jE6ns8AE+oNAGU3ldHpFJpVLplNp1PqFRqVTqlVo8uqwAKBHHBpORSDLMOpTCzTOpRCdmtFqtNnttrt1ssxSCrTOhSC7ROBRDTJrN/wGBwWDwmFqdYqxuMBHQa+SpMfTeY6gfzdY6fyuXzKezedy2cy2Y0L+ai3Qr9WB9Ej4w2t12v2Gx1oL2gS2gL2212+53G73ZeJ40RzKUxnfz8fb6fz2eLmfz1eDifz0d7h6bucHX7Lzdrff3c7z3ejrfzucTOfyzPwgf2y93v+Hx94IAwBJ/0AJRBP1KX7AL+v4/0AP+JIZAYVpik8LLynKaJ/HAZpRn8b5mMwcZolQfxymsWENGqV5/HIahWn8cZplXBhmn8drzn8WQ+A49r5RnGkaxsppOjiEp0FCOYQniUQ5A6eZRDiDciDiDUkSUUI4SUVI6AyfBYj0DMXRgfxYjzKxbkMFp/GgWI5n8cxsFnD0QRFEkTRQdxyxVFj0RfGMbzrO07viWY/hKfbLFAfp0m2YR/UDQdC0JQVEUMbRgn8dBsl/Rxsl9RxsUoYRLiWfxoliO7pne7x5HUbB/HidBqn8eB0Go5Z4nLFcWznGU8VpWtbKyWo/hCf7zPQ6ByH8d5zmlYNh2Kadj2TYViHgdJrH85J8H8YxPCxMBYjs5Z5nQ7TvnYbtvG4fx"
    s = s + "7nmdVYTlLFb3Vdd2KSWg/A8f84xTEsTxDEd7xJNV83uVkNGvM59nyetp2qfxnFeONPm9Up1WfVVkVVYh6njYF51lduM41dV33jeZ3nMaEQw5DRrFlf+TnKa+U5XkpYzIbJb2hgeC2sZpWDcfx5HWa9iwceGQ2DoLoHHc8rzpjek6VG2O3lFrxXMedvumduGHo7uqO9q+taq67vOQ5VqWsZhVDTVJ1VQep3OsfR8HpaB9Hu4+BaNjGl7vvDZabeZ7HmdOdHWbXAG3nR2XEeR2cJxHFHXwjuXA5B85qfxllOMuG1YfB6nefxw8qfxmlUNh/G4YhM7qPoPVnvPWdawO9xbilgYlVJ0WYdFkHf22fd5ZtUORaWxH84gw1Sc+RHyex5cmZJSeKb5lFIypmlkepLjWDpr9d7fuKp2D0Oo7x2nIZUVnIZfzfRYRn1SdNUHjUfC8JyPJmWVLjZ3Um4nmf3mjEP4cQ0BXQAGqMEegsRMhyGiGIKALg/PdghBEpb33CriHUOAYg/oLjFg1BhnT8TxHkHyuQfzyR4nHOQP4y4WlNiyDzCU5kMITwmg0N4ZY+xXCUDQNIMATQVB8glEGIRK4KDyHSz1QIu1EC8UQLpVo50yDWFy5QU4Zh/C9EiEA5Y8IoDIFGGAfxpgVj+F8JIIUZBIhBjJGYfwnQ7g0GmGIKYOw7ATAkBEkUQ49RBgpFxYg5mAJkkCOZkxy4jD+GuLwRo/hhiZCeg8ZYplgoXH8KcQoSxrBzC8DkSY"
    s = s + "Uglg+C7J6UEoguhBB4DIJQIQQAdBJHuV0Q1cq7V6dM6LQn2DvHLLeXI/h8D2HgiUaCHVICRfMNUfQuRQB1G4G4LoQhCgsBSCMnEr5qTVKQnoEg+0ICqH6vNFicBwzgTgOKcZ6ENi8H2MkWQix0huCuDERwJQRgfBTNae09yTisD6Ckd4sg/TZPUB89IfQOtHoMLIPqMT1OqFUHhH4jA1AsF8BUCgEwLT4oxRkioPiV0cI6R8kJGSSEkI0PAqxD6M0pVqQE"
    control.Images s
  • loads icons from a Microsoft ImageList control (MSComctlLib.ImageList of MSCOMCTL.OCX, method 1)
    control.Images imageList.Object
  • loads icons from a Microsoft ImageList control (MSComctlLib.ImageList of MSCOMCTL.OCX, method 2)
    Dim img As Object
    For Each img In imageList.ListImages
        control.Images img.Picture
    Next

where:

  • control, is the name of the control to load icons into, such as Grid1, Tree1, G2antt1, ...
  • imageList, is the name of Microsoft ImageList object to loads icons from such as ImageList1 (MSComctlLib.ImageList of MSCOMCTL.OCX)

The following C++ sample loads icons from HIMAGELIST:

HIMAGELIST hImageList = ImageList_Create(16, 16, ILC_MASK, 0, 0);
ImageList_ReplaceIcon(hImageList, -1, LoadIcon( theApp.m_hInstance, MAKEINTRESOURCE( IDR_MAINFRAME ) ));
m_spControl->Images( (LONG_PTR)hImageList );
ImageList_Destroy(hImageList);

where:

  • m_spControl is a member of EXCONTROLLib::IControlPtr type such as EXGRIDLib::IGridPtr, EXTREELib::ITreePtr, EXG2ANTTLib::IG2anttPtr, ... previously initialized by a code such as m_spControl = GetDlgItem(IDC_CONTROL1)->GetControlUnknown(); ( requires #import <ExGrid.dll>, #import <ExTree.dll>, #import <ExG2antt.dll>, ... )
  • IDR_MAINFRAME indicates the identifier of the ICON to load from the application's resources (theApp.m_hInstance)

The following C# sample loads icons from System.Windows.Forms.ImageList (available for /NET assemblies only such as eXGrid/NET, eXTree/NET, eXG2antt/NET, ...)

excontrol.Images(imageList);

where:

  • excontrol, is the name of the assembly to load icons into, such as exgrid1 (exontrol.EXGRIDLib.exgrid type), extree1(exontrol.EXTREELib.extree type), exg2antt1 (exontrol.EXG2ANTTLib.exg2antt type), ...
  • imageList, is the name of  System.Windows.Forms.ImageList object to loads icons from such as imageList1

The following VB.NET sample loads icons from System.Windows.Forms.ImageList (available for /NET assemblies only such as eXGrid/NET, eXTree/NET, eXG2antt/NET, ...)

Excontrol.Images(ImageList)

where:

  • Excontrol, is the name of the assembly to load icons into, such as Exgrid1 (exontrol.EXGRIDLib.exgrid type), Extree1(exontrol.EXTREELib.extree type), Exg2antt1 (exontrol.EXG2ANTTLib.exg2antt type), ...
  • ImageList, is the name of  System.Windows.Forms.ImageList object to loads icons from such as ImageList1

Once the control loads an icon it can be shown using its index (1-based) within the ex-HTML captions, such as "<img>1</img> Title", that displays the first icon from the control's Images collection. In order to use or display another type of picture such as PNG, JPG, JPEG, GIF, TIFF and so on, you must load it using the HTMLPicture method (loads a custom-size picture and associates a key to it). In case the icon or the picture has not been loaded the <img> tag displays instead the index or the key of the picture such as

ALL.41:

The Images method sets the control's images (icons) list at runtime. By default, the size of the icons in the control's image list is 16 x 16 pixels for DPI 100%, 20 x 20 for DPI 125%, 24 x 24 for DPI 125%, and so on. The ICO file format is an image file format used for computer icons in Microsoft Windows. ICO files contain one or more small images at multiple sizes and color depths, such that they may be scaled appropriately. For different DPI settings, you have to provide icons in different sizes (16 x 16 pixels for DPI 100%, 20 x 20 for DPI 125%, 24 x 24 for DPI 125%, and so on). The "dpi" keyword within expressions determines the current DPI setting for your application. For instance, the FormatABC("dpi") returns the application's DPI setting, as a 1-based value. For instance, if current DPI setting is 100%, the dpi constant returns 1, if 150% it returns 1.5, and so on. For instance, the expression "dpi" returns the 1 if the DPI setting is 100%, or 1.5 in case, the DPI setting is 150%, for DPI-aware applications. The expression "dpi" always returns 1 for a DPI-Unaware application, no matter of the current DPI settings. The FormatABC method formats the A,B,C values based on the giving expression and returns the result.

Exg2antt1.FormatABC("dpi", Nothing, Nothing, Nothing)

You can check the icon's appearance for different DPI settings using the ExImages tool (drag and drop the ICO file to the 1(IconList) panel and select a different DPI setting from 100% to 300%)..

The ExImages tool is a BASE64 encoder/decoder tool that helps you generate encoded-BASE64 strings for Images, VisualAppearance.Add, HTMLPicture, ... methods from icons, EBN or any picture files

See Also:

DPI-Aware
Load icons using the Images or ReplaceIcon method

ALL.42:

Generally, the object's tooltip can be set during initialization time using the ToolTipText, CellToolTip, ItemBar(exBarToolTip), ... but could be slower, so the following code shows how you can display the object's tooltip only when the cursor hovers it. Most of our controls provide the ShowToolTip method that shows the specified tooltip at giving position. The solution is using a timer as in the following samples.

VB:

Dim j As Long

Private Sub Form_Load()
    j = 0
    Timer1.Enabled = False
    Timer1.Interval = 128
End Sub

Private Sub G2antt1_MouseMove(Button As Integer, Shift As Integer, X As Single, Y As Single)
    If (j = 0) Then
        Timer1.Enabled = False
        Timer1.Enabled = True
    End If
End Sub

Private Sub Timer1_Timer()
    Timer1.Enabled = False
    j = j + 1
    G2antt1.ShowToolTip "Aka"
    j = j - 1
End Sub

VB/NET:

Private j As Integer = 0

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    Timer1.Enabled = False
    Timer1.Interval = 128
End Sub

Private Sub Exg2antt1_MouseMoveEvent(sender As Object, Button As Short, Shift As Short, X As Integer, Y As Integer) Handles Exg2antt1.MouseMoveEvent
    If (j = 0) Then
        Timer1.Enabled = False
        Timer1.Enabled = True
    End If
End Sub

Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
    Timer1.Enabled = False
    j = j + 1
    Exg2antt1.ShowToolTip("aka", Nothing, Nothing, "+8", "+8")
    j = j - 1
End Sub

C++:

int j = 0;
void CTestDlg::MouseMoveG2antt1(short Button, short Shift, long X, long Y)
{
  if ( !j )
    SetTimer(1000, 128, NULL);
}

void CTestDlg::OnTimer(UINT_PTR nIDEvent)
{
  if ( nIDEvent == 1000 )
  {
    KillTimer(nIDEvent);
    j++;
    m_spG2antt->ShowToolTip( _T("Aka"), vtMissing, vtMissing, _T("+8"), _T("+8"));
    j--;
  }
  CDialog::OnTimer(nIDEvent);
}

The samples re-start the timer (of 128 ms interval) every time the control's MouseMove event occurs. The actually call of ShowToolTip method is performed during the Timer's handler, so it is called once no matter how many time the MouseMove event occurs.

ALL.43:

The tooltip for the item bar appears after the bar remains stationary for a period of ToolTipDelay milliseconds and persists for ToolTipPopDelay milliseconds or until the mouse moves outside the item bar. Once hidden, the tooltip will reappear only when the mouse re-enters the item bar area; if the mouse remains inside the item bar, it must be moved out and back in to trigger the tooltip display again.

ALL.44:

When your application requires to load thousands of items it is important to follow these guidelines:

  • always use the BeginUpdate and EndUpdate methods to prevent the control from being redrawn while items are being loaded
  • prevent any events from firing while loading data by using the FreezeEvents method. Call FreezeEvents(True) before loading the data and FreezeEvents(False) once the loading is complete
  • use InsertItem/PutItems instead using the SetParent method
  • store the results of Items, Columns.Count, properties etc., into variables to avoid frequent calls
  • opt for arrays when you have data for the columns instead of iterating through them individually, so go for hLast = .InsertItem(h, , getArray()), instead of hLast = .InsertItem(h) : For j = 0 To nColumns - 1 : .CellValue(hLast, j) = val : Next
  • In Microsoft Access, ensure that the ID and Parent-ID fields of the table have their Indexed property set to "Yes" if you are using the virtual tree method to load a hierarchy (The Indexed property in Microsoft Access specifies whether an index should be created on a field in a table. Indexing a field creates a data structure that improves the speed of data retrieval and querying operations.)

No matter which method you use to load the data (Data, LoadXML, DataSource, PutItems, etc.), it is important to follow these guidelines to achieve the best possible speed.

See Also:

How to load a hierarchy using the control's DataSource property?

ALL.45:

A Gantt chart is a time-phased graphic display of activity durations. Activities are listed with other tabular information on the left side, with time intervals over the bars. Activity durations are shown as horizontal bars. We provide three Gantt chart controls as listed below:

  • The ExG2Host is an extension of ExG2antt with full database support (ADO, DAO, XML). This means ExG2Host can automatically load and save the host's data, including the hierarchy, to one or more databases. You can map a data field from the data source to a property of an object in the host/Gantt control, and the control updates the field as needed. Similarly, you can save the control's layout so that it displays the same way when reopened. By default, the ExG2Host component allows you to add, remove, and edit items, child items, tasks, links, and more without additional coding. The ExG2Host component supports all features of the ExG2antt component. Available as /COM only.
  • The ExG2antt is a standalone component for displaying and editing Gantt charts, which are time-phased graphic displays of activity durations. The ExG2antt is a superset of ExGantt, meaning it includes all features of ExGantt.
  • The ExGantt is a read-only Gantt chart control.

The /NET version provides the following methods for data binding:

  • DataSource, gets or sets the data source that the control is displaying data for. By default, this property is empty object. The DataSource property can be: DataTable, DataView, DataSet, DataViewManager, any component that implements the IListSource interface, or any component that implements the IList interface.
  • DataMember, indicates a sub-list of the DataSource to show in the control. By default, this property is "". For instance, if DataSource property is a DataSet, the DataMember should indicates the name of the table to be loaded.
  • DataTaskStart, The DataTaskStart property gets or sets the specific field in the data source to indicate the starting point of each added task. If missing or empty, no tasks are loaded during binding. In other words, it indicates the field to use be used as the starting point for each task in any record. This member is automatically filled with the first DATE field from the DataSource, when it is set. This member is automatically filled with the first DATE field from the data source ( DataSource/DataMember ).
  • DataTaskEnd, DataTaskEnd property gets or sets the specific field in the data source to indicate the ending point of each added task. If missing or empty, no tasks are loaded during binding. If the DataTaskEnd points to a DateTime object, it indicates the ending date of the newly bar, else, it indicates the duration of the task to be added. If the DataTaskEnd is equal with DataTaskBegin, a one-day task is added for each record found, during binding. This member is automatically filled with the second DATE field from the DataSource collection. This member can be of DATE type, which indicates the exBarEnd property of any bar in the collection, or a DOUBLE, when it indicates the length/duration of the bar to be added.

See Also:

How to load a hierarchy using the control's DataSource property?

ALL.46:

Currently, when users hold down a key to scroll left, the scrolling continues due to the command being repeated by the buffering. Disabling buffering for movement commands would help prevent this issue.

Dim k As Integer

Private Sub Grid1_KeyDown(KeyCode As Integer, Shift As Integer)
    If Not (KeyCode = k) Then
        k = KeyCode
    Else
        KeyCode = 0
    End If
End Sub

Private Sub Grid1_KeyUp(KeyCode As Integer, Shift As Integer)
    k = -1
End Sub
The sample disables executing the key while the user presses it.
ALL.47:

An assembly manifest is a key part of a .NET or COM assembly that provides important metadata about the assembly. It describes the assembly's identity, versioning, security permissions, dependencies, and other critical information needed for its execution. The manifest ensures that the application or components can be correctly loaded and executed by the runtime.

The assembly manifest file could look as follows:

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <assemblyIdentity name="expression.X" version="20.0.0.6" type="win32" processorArchitecture="x86"></assemblyIdentity>
  <file name="expression.dll" hashalg="SHA1">
    <comClass clsid="{B33F5489-49AC-4155-98E7-9BBFC57FF019}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" progid="Exontrol.Expression.1" description="Expression Class" miscStatusContent="recomposeonresize,cantlinkinside,insideout,activatewhenvisible,setclientsitefirst"></comClass>
    <comClass clsid="{4E83DAA1-94B2-4AB8-81B3-CEE5AF1D5D16}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" progid="Expression.ExDataObjectFiles.1" description="ExDataObjectFiles Class" ></comClass>
    <comClass clsid="{8828746B-AA2C-4D31-833F-D612E793ACB0}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" progid="Expression.ExDataObject.1" description="ExDataObject Class" ></comClass>
    <comClass clsid="{5D8F2282-A127-4076-858E-7C9F509164AD}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}"  description="TemplatePage Class" ></comClass>
    <comClass clsid="{F4DB5D1D-B4F6-4988-97CE-FDE672F6571E}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" progid="Expression.Appearance.1" description="Appearance Class" ></comClass>
    <typelib tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" version="1.0" helpdir="" flags="HASDISKIMAGE"></typelib>
  </file>
  <comInterfaceExternalProxyStub name="IExDataObjectFiles" iid="{275F8017-C012-4E11-A58A-34F796B8871B}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
  <comInterfaceExternalProxyStub name="IExpression" iid="{2D4A9F83-770A-41C1-BCA1-16D3A136D851}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
  <comInterfaceExternalProxyStub name="IAppearance" iid="{A422C36A-E5E1-417E-8A17-64474004D7CE}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
  <comInterfaceExternalProxyStub name="IExDataObject" iid="{C6EA1ECC-CE72-463C-B81C-29F567CD6257}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
</assembly>

To include additional controls in the same manifest file, you should generate each manifest individually and then copy the 'file' and 'comInterfaceExternalProxyStub' elements into the 'assembly', as shown in the following example.

<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
  <file name="expression.dll" hashalg="SHA1">
    <comClass clsid="{B33F5489-49AC-4155-98E7-9BBFC57FF019}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" progid="Exontrol.Expression.1" description="Expression Class" miscStatusContent="recomposeonresize,cantlinkinside,insideout,activatewhenvisible,setclientsitefirst"></comClass>
    <comClass clsid="{4E83DAA1-94B2-4AB8-81B3-CEE5AF1D5D16}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" progid="Expression.ExDataObjectFiles.1" description="ExDataObjectFiles Class" ></comClass>
    <comClass clsid="{8828746B-AA2C-4D31-833F-D612E793ACB0}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" progid="Expression.ExDataObject.1" description="ExDataObject Class" ></comClass>
    <comClass clsid="{5D8F2282-A127-4076-858E-7C9F509164AD}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}"  description="TemplatePage Class" ></comClass>
    <comClass clsid="{F4DB5D1D-B4F6-4988-97CE-FDE672F6571E}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" progid="Expression.Appearance.1" description="Appearance Class" ></comClass>
    <typelib tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" version="1.0" helpdir="" flags="HASDISKIMAGE"></typelib>
  </file>
  <comInterfaceExternalProxyStub name="IExDataObjectFiles" iid="{275F8017-C012-4E11-A58A-34F796B8871B}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
  <comInterfaceExternalProxyStub name="IExpression" iid="{2D4A9F83-770A-41C1-BCA1-16D3A136D851}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
  <comInterfaceExternalProxyStub name="IAppearance" iid="{A422C36A-E5E1-417E-8A17-64474004D7CE}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
  <comInterfaceExternalProxyStub name="IExDataObject" iid="{C6EA1ECC-CE72-463C-B81C-29F567CD6257}" tlbid="{166B2D4C-A3B3-46B6-A5C6-F2D6595BE6CA}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
  <file name="exedit.dll" hashalg="SHA1">
    <comClass clsid="{39136531-DD0F-4281-B445-E36FC2CDDBC5}" tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}" progid="Exontrol.Edit.1" description="Edit Class" miscStatusContent="recomposeonresize,cantlinkinside,insideout,activatewhenvisible,setclientsitefirst"></comClass>
    <comClass clsid="{03F2B067-BAC9-428C-A94F-768329F80EF3}" tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}" progid="ExEdit.Context.1" description="Context Class" ></comClass>
    <comClass clsid="{77274D04-DE10-4C06-8431-BEC91CBFC21C}" tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}" progid="ExEdit.ExDataObjectFiles.1" description="ExDataObjectFiles Class" ></comClass>
    <comClass clsid="{AC1F7078-CAD9-402E-9A2B-AB85495C47AD}" tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}" progid="ExEdit.ExDataObject.1" description="ExDataObject Class" ></comClass>
    <comClass clsid="{7241FC9A-A5C9-4D41-A44C-33561C522C61}" tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}"  description="TemplatePage Class" ></comClass>
    <comClass clsid="{48C5C1E5-1921-4F83-A38D-A84EA09780D7}" tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}" progid="ExEdit.Appearance.1" description="Appearance Class" ></comClass>
    <typelib tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}" version="1.0" helpdir="" flags="HASDISKIMAGE"></typelib>
  </file>
  <comInterfaceExternalProxyStub name="IExDataObjectFiles" iid="{626415B2-2D8C-42E5-BE13-CDDCA16D20D0}" tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
  <comInterfaceExternalProxyStub name="IExDataObject" iid="{7625D9A6-7491-47A9-9745-51B3DDDA8ADD}" tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
  <comInterfaceExternalProxyStub name="IEditContext" iid="{A8C1B25B-7EAE-4ADB-A01E-9C74881E2504}" tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
  <comInterfaceExternalProxyStub name="IEdit" iid="{B7152D58-325A-4586-B0CC-287D067355BC}" tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
  <comInterfaceExternalProxyStub name="IAppearance" iid="{DB133A97-9FE9-4ADD-AAF9-2D48EE87BD6C}" tlbid="{99AD4CAA-B101-4F05-A4A0-EF27437AB040}" proxyStubClsid32="{00020424-0000-0000-C000-000000000046}"></comInterfaceExternalProxyStub>
</assembly>

The 'name' attribute of the 'file' element can include the relative path to the DLL, as <file name="dll/exedit.dll" hashalg="SHA1">

See Also:

How to Generate Assembly Manifest File (Registration-Free)
Can I use the /COM version without registering on the client machine?

ALL.48:

An Assembly Manifest for COM (Component Object Model) is an XML-based file that provides critical metadata about a COM component, facilitating its registration and use within Windows applications. It plays a significant role in defining how COM components are integrated and utilized in software development.

To generate the assembly manifest for components not listed by ExHelper (such as Exontrol.EMail, etc.), you can follow these steps:

  • Open the eXHelper tool
  • Right-click the middle panel (the template panel) to display its context menu.
  • Hold the SHIFT key and select 'Generate Assembly Manifest'

An input box will appear asking for the CLSID of the object (e.g., Exontrol.EMail). The assembly manifest for the specified control will be generated and displayed. The CLSID of the object can be found:

  • under Identifier field on the control's main page
  • as a tip, refer to the control's help file under the main object (the one in bold), as "The /COM object can be placed on a HTML page (with usage of the HTML object tag: <object classid="clsid:...">) using the class identifier: ... The object's program identifier is: "...". The /COM object module is "..."

See Also:

How to Generate Assembly Manifest File (Registration-Free)
Can I use the /COM version without registering on the client machine?