Tech Note 11a: NS Basic Controls Overview

May 02, 2006

© NSB Corporation. All rights reserved.

NS BASIC Controls


NS BASIC Controls implements set of controls and helper classes. Together they enable the NSBasic developers to use a number of Windows Common Controls in their projects. The library will grow in time including more controls of this category. This documentation will be updated accordingly.

When a new version is published you can just replace the library's DLL in your application distributives. The backward compatibility between the versions is preserved and only new features and controls are added with each new version. Check for more general information in the FAQ.

1. The library contents

Insertable (visual) Controls Helper ActiveX objects.
These are the ActiveX controls you would want to put onto your forms. Usually you should put them in the NSBasic IDE's toolbox and then place them on the forms on which they will be used.   These are creatable ActiveX objects which have no visual appearance of their own at run time. They are used by the visual controls in this library to maintain certain common data. Most often you do not need to create them directly because the visual controls create them automatically and enable you work with them as if they are integral part of the control itself (see faq).

NSListView

ProgID: NSBasic.comctl.ListView
ClassID:
{F7A4DFE2-C262-457E-B0C5-B4789D02988D}
Create example: 
AddObject "NSBasic.comctl.ListView", "NSListView1", 312, 0, 328, 456, Form1

Note: It is more convenient to put it into the toolbox of the IDE first and then place it on the forms.
 

 

NSBImageList

ProgID: NSBasic.comctl.ImageList
ClassID: {E4FD27CF-BA94-452F-A486-82CFA4D09868}
Create example: 
AddObject "NSBasic.comctl.ImageList", "MyImageList1"

NSFont

ProgID: NSBasic.comctl.NSFont
ClassID: {07679CF2-323B-46A7-87CB-A8DC600BC4BE}
Create example:
AddObject "NSBasic.comctl.NSFont", "MyFont1"

How to add a control to the toolbox manually: Make sure that the Windows desktop  version of control's DLL (NSBControls.dll) is installed/registered on your desktop/notebook computer.  Open the ActiveX Control manager dialog box from the tool menu, browse for the DLL and add it. Note that for the both NSBasic development environments (Desktop and CE) the desktop version of the DLL is used at design time. The specific version for the device is needed only when the application is deployed. This is so, because the IDE uses only the registration information of the DLL and may need to query it for some information while you are developing the application on the desktop.

2. NS BASIC Controls FAQ

Q: Why put many controls in single DLL instead of putting each control in separate DLL?

A: Most of the controls in this library are complex and thus require common helper objects and facilities. Having them all in a single DLL makes the integration of all those objects easier and minimizes the impact over the performance. For example  NSBImageList objects are used by the NSListView control but they are also used by the NSTreeView control. Having separate DLL for each control will require implementation of image list in each of them and make it harder to share the same object between different kind of controls. When in single DLL the objects have the opportunity to create such objects directly and not through the standard COM API routines thus avoiding the ned to dig into the registry each time an object is created. Obviously in case of extensive usage of certain objects this improves the performance drastically. The DLL may be a bit bigger than usual but over a third of its size is occupied by code common to all the controls. Therefore splitting the controls in separate DLL-s will cause noticeable size overhead if more than one control is needed in any particular project.  

Q: How do the helper objects become integral parts of the controls?

A:  Let's illustrate this with the NSBImageList object. The NSListView control needs 3 such objects - one for each: the big item icons, small item icons and the column headings. When created NSListView implicitly creates 3 empty image lists - one for each purpose and exposes them through these properties:

  • Icons - the big icons
  • SmallIcons - the small icons and the icons in report view (both for items and subitems)
  • ColumnHeaderIcons - the icons for the column headings.

Thus when you need to load some images to display in the  NSListView you do not need to create an NSBImageList object. Instead you address the already existing object through the property that exposes it to you:

NSListView1.Icons.LoadBitmap "\myimages.bmp"

will load images into the big icons image list of the control. You can also change the sizes the same way:

' Note that usually this is done before loading any images, 
' because when the size changes all the existing images are deleted.
NSListView1.Icons.Width = 48
NSListView1.Icons.Height = 48

So, effectively you can consider the image list integral part of the control. In the NSListView there are 3 such integral parts and you can manage them through the corresponding property.

Is it possible to replace such an object in the control? Yes! You can create a NSBImageList separately or get it from another object on the form and assign it to the control. Suppose we have two list views on the same form:

Set NSListView2.SmallIcons = NSListView1.SmallIcons

will assign the small icons image list from the first list view control to the second and both list views will share the same object. This is especially helpful when you want to use the same set of images in different controls.

Creating object such as NSBImageList explicitly is rarely needed. One of the cases in which it would make sense is a scenario in which you are adding control dynamically to the form. In such case you may want to have the images already prepared before adding the new control(s). However, this is extremely untypical.

Q: What are these Tag properties for?

Almost all the objects in the NS BASIC Controls library has this property. The application can save in it whatever it wants and then access it later. This means that you can assign to a Tag property a simple value (such as string) or Set an object - it is up to you. Further this Tag can be used to tag an element in a control or help the application recognize the element in some convenient way. The Tag can be used for many purposes, but we will try to emphasize two of the most interesting ones:

Handling events: A good example is the NSListView control. Its events carry single argument - a NSListViewEvent object which has several properties that can be empty or filled with something. That something is the control's element or elements relevant to the event.  Thus handling the vent you can access an element relevant to it directly. For example:

Sub NSListView1_OnClick(e)
  e.Item.Text = "I have been clicked!"
End Sub

This code changes the text of the clicked item to "I have been clicked!". In this sample code there is no indexing - the item that  have been clicked is in the event object and you can work with it directly regardless of its index in the control. In the real world the items carry some meaning and very often the application needs to establish a relation between the item and other data. For example if the items represent the rows from the result returned by a database query you may want to "attach" each row to its item. Lets illustrate this with an example. Assume you have SQLite COM or SQLite3 COM database opened (the db variable holds the DB connection object):

Set res = db.Execute("SELECT * FROM T")
For Each row In res
   Set itm = NSListView1.ListItems.Add(,,row("FIRST_NAME"))
   Set itm.Tag = row
Next

In this code we add one item for each row in the result of the query. For brevity we only assign a text to each item (no icons or other goodies). Then we also assign the row to the Tag property of the item. Thus we have each row attached to its item. Visually the item uses one of the fields from the result as a text label, but internally we keep a reference to the entire row and we can access it through the Tag property whenever we want. When we would want to do so? Again when handling events, but also we may want to do the same when we do something else - such as enumerating the items, searching for items and then access the DB row for each found item and so on. Most clear is the event handling case (lets use OnClick again):

Sub NSListView1_OnClick(e)
  Dim s
  s = ""
  For I = 1 To e.Item.Tag.Count
    s = s & e.Item.Tag.Key(I) & "=" & e.Item.Tag(I) & vbCrLf
  Next
  MsgBox s
End Sub

We simply show a message box with all the fields in the row in Name=Value format. Note that we know that the Tag contains a row from the previously extracted data from the DB, thus we can use over it the Count property to see how many fields are there and the Key property to get the name for each field. 

Obviously without the Tag property in the above example we will need to make complex and sometimes risky calculations to identify the row that corresponds to an item.  Why risky? Imagine the application decides to add items generated the same way for another query, not removing the already existing items first. Then we have two data sets and many items which may have been sorted visually before we access them again. The index of an item will be of no use after all the visual sorting - no index to row relation is preserved and remember we have two datasets used, so which one corresponds to a particular item... With the tags the data is attached to the item and we have everything at hand.

Sorting and searching: This applies to some objects only (such as Item and SubItem in the NSListView control). The NSListView.FindItems method and the sorting functions of this control support search/sort by text or Tag. Very often the application would need to show the user one text and keep in the background another data that is more convenient for processing. The best examples are scenarios in which you want to show the user values marked with measurement units. For example file size rounded to KBytes or MBytes as appropriate for each individual value, or another example weight - again some values will be rounded to grams other to kilograms and so on. The texts shown to the user are not numbers and cannot be sorted or searched as such without complicated string parsing - specific for each individual similar scenario. Sorting them as texts will be ridiculous 1g and 1kg will appear both smaller than 2g and 2kg which is not exactly true. So, the simplest solution is to save convenient numeric or text value in the Tag property of each item/subitem and then search/sort over the contents of the Tag properties and not the texts - which remain only visual labels for human consumption. 

What if we want to combine both - keep for example entire row of data (as in the example above) and also use the Tag-s for sorting/searching. Is it possible? Almost always - yes! When the sorting and the searching functions use the Tag properties of the elements in the control they do not require the Tag property to contain plain string or a number. Instead you may have an object there (an entire row of data for example) which have default property that returns text or numeric value (as appropriate for the sort or search you want to perform). In the case with the SQLite COM/SQLite3 COM the results are packed using VarDictionary objects from newObjects ActiveX Pack1. Thus each row is a VarDictionary object which is actually a general purpose collection/dictionary object and can be configured to behave the way you want it. For the purposes of this example we want the default property of such a row of data to return something sensible. Lets modify the code from the above example a little:

Set res = db.Execute("SELECT * FROM T")
For Each row In res
   Set itm = NSListView1.ListItems.Add(,,row("FIRST_NAME"))
   row.Root = row("LAST_NAME")
   Set itm.Tag = row
Next

The VarDictionary's Root property specifies what default value should be returned by the object when it is queried for its default property without index (when index is used the indexed element is returned). Thus by assigning the value of a specific field to it we ensure that the sorts or the searches in the NSListView controls will be done over the text in that field. Remember how we want to have one text shown to the user and another actually used for sorting - we achieved that (frankly in a bit weird way in this example) - the item shows the FIRST_NAME, but any sorts using the Tag property will occur over the LAST_NAME. 

Conclusion: The Tag properties are powerful way to create relations between visible elements and data managed by the application internally. They enable the developer to avoid complex index calculations and can be used to tune the behavior of some controls according to the actual meaning of the information and not its human readable representation. While it is hard to estimate it exactly in a typical application Tag based implementation would require at least 2-3 times less code than index based data to visual elements relation implementation. And note that this means that by choosing appropriate values for the Tag-s you are free to perform whatever visual operations you want without losing the relation with the internal data  - this enables you to provide more user friendly features without concern about the rest of the work the application does.

3. Supported platforms and compatibility

The library is available as single DLL named: NSBControls.dll.

All the ActiveX controls in this library look the same way to the application on each platform. The actual functionality is virtually the same on both desktop and Windows CE/CE.NET devices. There are only a couple of tiny cosmetic differences that does not concern the controls' behavior (see the notes in the page of the corresponding control).