The eXCascadeTree component is a multiple-columns-tree-view component that uses miller columns visualization to display your data. The Miller columns (also known as Cascading Lists) are a browsing/visualization technique that can be applied to tree structures. The cascade columns allow multiple levels of the hierarchy to be open at once, and provide a visual representation of the current location.
The control can automatically handle Array, XML, ADO, DAO, DataSet through the
DataSource properties ( control and view objects ). You can specify
the data source for the entire control through the DataSource property,
or for a particular view using View.DataSource property. If an internal
error occurs while using the DataSource property the Error event
occurs.
For instance,
"...\sample.xml" opens the
sample.xml file
"...\sample.dbf" opens the
specified sample.dbf table
"
Data Member=SELECT * FROM Orders ; Data
Source=...\sample.accdb
", opens the Orders table of the
specified sample.accdb database
"
Data Member=SELECT * FROM Orders ; Data
Source=...\sample.mdb
", opens the Orders table of the
specified sample.mdb database
"
Data Member=Orders ; Driver={Microsoft Access Driver (*.mdb)}
; DBQ=...\sample.mdb
", opens the Orders table of sample.mdb
database, using ODBC
"
Data Member=Orders ; Driver={Microsoft Access Driver (*.mdb)}
; DBQ=...\sample.mdb
", opens the Orders table of sample.mdb
database, using ODBC
"
Data Member=SELECT * FROM [Sheet1$] ;
Driver={Microsoft Excel Driver (*.xls)} ; DBQ=...\sample.xls ; DriverID=790
" reads
the Sheet1 worksheet of the sample.xml file ( Excel )
"Source=...\sample.mdb;Member=Select * FROM Countries;Key=CountryCode;Tag=Country;Name=CountryName >>> Member=Select * FROM States WHERE CountryCode IN (<%Parent.CountryCode%>);Key=StateCode;Name=StateName;Tag=State ||| Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.CountryCode%>);Tag=City;Name=Name >>> Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.Parent.CountryCode%>) AND StateCode IN (<%Parent.StateCode%>);Tag=City;Name=Name",
specifies multiple-data sources for Country, State and City
views
where ... indicates the full path to the sample file.
The control's DataSource property in BNF syntax is:
In other words, the DataSource property provides data source for each
view separated by >>> sequence, and for each view different
alternatives to create the view separated by ||| sequence. The
DataSource can include sequences between <% and %> which are filled
at runtime, based on the current selection in all views.
Let's examine the following DataSource sequence:
"Source=...\cities.mdb ; Member=Select * FROM Countries ;
Key=CountryCode ; Tag=Country ; Name=CountryName >>> Member=Select * FROM States WHERE CountryCode IN (<%Parent.CountryCode%>) ;
Key=StateCode ; Name=StateName ; Tag=State ||| Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.CountryCode%>) ;
Tag=City ; Name=Name >>> Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.Parent.CountryCode%>) AND StateCode IN (<%Parent.StateCode%>) ;
Tag=City ; Name=Name "
which can generate data source for up to 3 views red (country), green
(state/city) and blue(city) as follows:
"Source=...\cities.mdb ;
Member=Select * FROM Countries ;
Key=CountryCode ; Tag=Country ; Name=CountryName
>>>
Member=Select * FROM States WHERE CountryCode IN (<%Parent.CountryCode%>) ;
Key=StateCode ; Name=StateName ; Tag=State
|||
Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.CountryCode%>) ;
Tag=City ; Name=Name
>>>
Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.Parent.CountryCode%>) AND StateCode IN (<%Parent.StateCode%>) ;
Tag=City ; Name=Name "
At runtime, these three views may shows as:
In the same time, each view's DataSource shows as:
View("Country").DataSource = "Member=Select * FROM
Countries ; Key=CountryCode ; Tag=Country ; Name=CountryName
;
Source=...\cities.mdb"
View("State").DataSource = "Member=Select * FROM States WHERE CountryCode IN
('US') ; Key=StateCode ; Name=StateName;Tag=State
;
Source=...\cities.mdb"
View("City").DataSource = "Member=Select * FROM Cities WHERE CountryCode IN
('US') AND StateCode IN ('AZ','FL','CO','HI','IN')
; Tag=City ; Name=Name ;
Source=...\cities.mdb"
For instance, Antartica has no states, the Member=Select * FROM States WHERE CountryCode IN (<%Parent.CountryCode%>)
generates no results, and so the alternative data source is used Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.CountryCode%>),
so at runtime the views may shows as:
In the same time, each view's DataSource shows as:
View("Country").DataSource = "Member=Select * FROM
Countries ; Key=CountryCode ; Tag=Country ; Name=CountryName
;
Source=...\cities.mdb"
View("City").DataSource = "Member=Select * FROM Cities WHERE CountryCode IN
('AQ') ; Tag=City ; Name=Name ;
Source=...\cities.mdb"
Internally, the control's DataSource builds the view's DataSource with
code as follows:
Private Sub CascadeTree1_CreateView(ByVal View As Object)
With View
Select Case View.Index
Case 1: ' State or City
.DataSource = CurrentDb.OpenRecordset("Select * FROM States WHERE CountryCode IN (" & .ParentView.ValueList("CountryCode") & " )")
.Key = "StateCode"
.Name = "StateName"
.Tag = "State"
If (.Items.ItemCount = 0) Then
.DataSource = CurrentDb.OpenRecordset("Select * FROM Cities WHERE CountryCode IN (" & .ParentView.ValueList("CountryCode") & " )")
.Key = ""
.Tag = "City"
.Name = "Name"
End If
Case 2: ' City
.DataSource = CurrentDb.OpenRecordset("Select * FROM Cities WHERE CountryCode IN (" & .ParentView.ParentView.ValueList("CountryCode") & ") AND StateCode IN (" & .ParentView.ValueList("StateCode") & ")")
.Key = ""
.Tag = "City"
.Name = "Name"
End Select
End With
End Sub
Private Sub Form_Load()
With CascadeTree1
.BeginUpdate
With .DefaultView
.DataSource = CurrentDb.OpenRecordset("SELECT * FROM Countries")
.Key = "CountryCode"
.Tag = "Country"
.Name = "CountryName"
End With
.EndUpdate
End With
End Sub
The DataSource property supports the following fields:
Source or Data Source, specifies the data source type,
usually a MDB or ACCDB, but could be XLS, TXT or else. For instance,
"Source=C:\Program Files\Exontrol\ExCascadeTree\Sample\Access\cities.accdb"
refers to the cities.accdb database. The Source or Data Source field
is required, else an error occurs ( see Error event ).
Member of Data Member, indicates the SELECT SQL
statement to be created from the Data Source. For instance, "Member=Select * FROM Countries",
creates a view with all records from the Countries table. The Member
or Data Member field is required, else an error occurs ( see Error
event ). While this is not a requirement the DataSource can include
ANYWHERE sequences between <% and %> characters
that specifies a runtime-generated string based on the current
selection into your views. For instance, "Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.Parent.CountryCode%>) AND StateCode IN (<%Parent.StateCode%>)"
Each sequence between <% and %> characters
indicates the value of the current selection into a specified View
of the specified Column/Field, and must be of the following BNF syntax:
<value> ::= "<%" <view> "." <column> "%>"
<view> ::= <parentview> [ "." <parentview> | <indexview>
<parentview> := "Parent"
<indexview> := 0 | 1 | 2 | ...
<column> := <index> | <name>
<index> := any index of any field into the Data Member
<name> := any name of the field into the Data Member / any caption of the column into the view
For instance:
<%Parent.StateCode%>,
indicates the value of the selection into the parent view of the
column "StateCode".
<%0.CountryCode%>,
indicates the value of the selection into the view with the
index 0 of the column "CountryCode".
<%Parent.Parent.CountryCode%>,
indicates the value of the selection into the parent of the
parent view of the column "CountryCode".
<%1.2%>,
indicates the value of the selection into view with the index 1,
on the column with the index 2
The View.ValueList property generates the values on the specified
column ( Key column ) for all selected items, separated by , (comma)
character. The ValueList property automatically includes ' character
for strings and # for date fields. For instance, "'AZ','FL','CO','HI','IN'"
or "1,2"
Key or Data Key, specifies the index or the name of
the field from the Data Member that generates keys for the current
view. For instance, "Key=CountryCode"
specifies that the CountryCode field of the current view generates
keys for next child views. The Key property of the View object can be
used to access the key of the view at runtime. If the Key refers to an
exiting field/column in the current view, it means that the control
generates the next view, once the user selects one or more items into
the current view. If the Key is empty or points to an non-existing
field/column in the current view, no view will be generated once an
item in the current view is selected. The control fires the CreateView
event once a new view requires to be created. The
ViewStartChanging(exSelectChange) / ViewEndChanging(exSelectChange)
event notifies your application once the selection into the view is changing.
During any event, you can access the view that generated the event,
using the View property of the control. The Select property of the
control generates the path of the current selection for all views
using the Key property of each View ( separated by \ backslash
character ). For instance, the Select property could return "US\AK".
The Key field is not required, and if missing no view will be
generated once the user selects an item into the current view.
Name or Data Name, indicates the index or the name of
the field from the Data Member, that generates names for the Name
property. For instance, "Name=CountryName",
indicates that the CountryName column of the current view generate
values for the Name property. The Name property of the control
generates the path of the current selection for all views using the
Name property of each View ( separated by \ backslash character ). For
instance, the Name property could return "United States\Alaska\Anchorage",
The Name field is not required. By default, the column with the index
0 specifies the name column.
Tag or Data Tag, specifies any extra data associated
with the view. For instance, "Tag=Country".
The Tag property of the View can be used to access the tag of the view
at runtime. The Tag field is not required.
or any additional field like DBQ, Driver,
DriverID,
Server, SourceType, SourceDB
as specified by your connection
string.
The Error event notifies your application once any internal error
occurs. You can use the Description parameter of the Error event to find
out more information about connection your data to the control.
Also the DataSource supports any of the following type of objects:
Safe-Array:
With CascadeTree1.DefaultView
.LinesAtRoot = exLinesAtRoot
.DataSource = Array("Item 1", Array("Sub-Item 1", "Sub-Item 2"), "Item 2")
End With
/NET or /WPF Version (VB)
With Excascadetree1.DefaultView
.LinesAtRoot = exLinesAtRoot
.DataSource = New Object() {"Item 1", New Object() {"Sub-Item 1", "Sub-Item 2"}, "Item 2"}
End With
adds items from a safe-array. If it includes inside-safe arrays, it
adds child items, and so on.
XML file name, a URL, an IStream, an IXMLDOMDocument
With CascadeTree1
.DataSource = "C:\Program Files\Exontrol\ExCascadeTree\Sample\testing.xml"
End With
or:
With CascadeTree1.DefaultView
.DataSource = "C:\Program Files\Exontrol\ExCascadeTree\Sample\testing.xml"
End With
or:
With CascadeTree1.DefaultView
Set xml = CreateObject("MSXML.DOMDocument")
With xml
.Load "C:\Program Files\Exontrol\ExCascadeTree\Sample\testing.xml"
End With
.DataSource = xml
End With
ADO (Jet):
With CascadeTree1
Set ado = CreateObject("ADODB.Recordset")
With ado
.Open "Countries", "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program Files\Exontrol\ExCascadeTree\Sample\Access\cities.mdb", 3, 3
End With
.DataSource = ado
End With
or:
With CascadeTree1
Set ado = CreateObject("ADODB.Recordset")
With ado
.Open "Countries", "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Program Files\Exontrol\ExCascadeTree\Sample\Access\cities.mdb", 3, 3
End With
.DefaultView.DataSource = ado
End With
ADO (OLEDB):
With CascadeTree1
Set ado = CreateObject("ADODB.Recordset")
With ado
.Open "Countries", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Program Files\Exontrol\ExCascadeTree\Sample\Access\cities.accdb", 3, 3
End With
.DataSource = ado
End With
or:
With CascadeTree1
Set ado = CreateObject("ADODB.Recordset")
With ado
.Open "Countries", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Program Files\Exontrol\ExCascadeTree\Sample\Access\cities.accdb", 3, 3
End With
.DefaultView.DataSource = ado
End With
DAO:
With CascadeTree1
.DataSource = CurrentDb.OpenRecordset("Countries")
End With
or:
With CascadeTree1.DefaultView
.DataSource = CurrentDb.OpenRecordset("Countries")
End With
As Microsoft Access uses DAO, you need to use the View's DataSource
property rather than control's DataSource property as in the following
sample:
Private Sub CascadeTree1_CreateView(ByVal View As Object)
With View
Select Case .Index
Case 1: ' State or City
.DataSource = CurrentDb.OpenRecordset("Select * FROM States WHERE CountryCode IN (" & .ParentView.ValueList("CountryCode") & " )")
.Tag = "State"
.Key = "StateCode"
.Name = "StateName"
If (.Items.ItemCount = 0) Then
.DataSource = CurrentDb.OpenRecordset("Select * FROM Cities WHERE CountryCode IN (" & .ParentView.ValueList("CountryCode") & " )")
.Tag = "City"
.Key = ""
.Name = "Name"
.ColumnAutoResize = False
End If
Case 2: ' City
.DataSource = CurrentDb.OpenRecordset("Select * FROM Cities WHERE CountryCode IN (" & .ParentView.ParentView.ValueList("CountryCode") & ") AND StateCode IN (" & .ParentView.ValueList("StateCode") & ")")
.Tag = "City"
.Key = ""
.Name = "Name"
End Select
End With
End Sub
Private Sub Form_Load()
With CascadeTree1.DefaultView
.DataSource = CurrentDb.OpenRecordset("SELECT * FROM Countries")
.Tag = "Country"
.Key = "CountryCode"
.Name = "CountryName"
End With
End Sub
The sample loads the Countries table into the default view ( view with
the index 0 ). Once the user clicks / selects / activates an item, the
control creates a new view ( with the index 1, 2 and so on ) and fires the
CreateView event. During the CreateView event you can load data from
different tables based on the parent's view selection. See the
ParentView.ValueList
The "Provider cannot be found. It may not be properly
installed" error could occur if no ADO is installed for your system.
For instance, you are running the exhelper on x64 machine, and using an
MDB which work on 32-bit environment only.
Let's say we have data source such as:
"Source=C:\Program Files\Exontrol\ExCascadeTree\Sample\Access\cities.mdb;Member=Select * FROM
Countries;Key=CountryCode;Tag=Country;Name=CountryName
>>>Member=Select * FROM States WHERE CountryCode IN (<%Parent.CountryCode%>);Key=StateCode;Name=StateName;Tag=State ||| Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.CountryCode%>);Tag=City;Name=Name
>>>Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.Parent.CountryCode%>) AND StateCode IN (<%Parent.StateCode%>);Tag=City;Name=Name"
so change the mdb to ACCDB so it should be such as:
"Source=C:\Program Files\Exontrol\ExCascadeTree\Sample\Access\cities.accdb;Member=Select * FROM
Countries;Key=CountryCode;Tag=Country;Name=CountryName
>>>Member=Select * FROM States WHERE CountryCode IN (<%Parent.CountryCode%>);Key=StateCode;Name=StateName;Tag=State ||| Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.CountryCode%>);Tag=City;Name=Name
>>>Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.Parent.CountryCode%>) AND StateCode IN (<%Parent.StateCode%>);Tag=City;Name=Name"
If you still get the same error, make sure that you have installed any ADO
on your machine.
Currently, the DataSource property automatically finds the provider for the XML,
MDB, ACCDB or DBF
extensions. In case you are using a different type of file this error may
occurs, so you need to provide the proper data provider using Data Member,
Driver, DBQ, DriverID ... fields.
For instance, here's a snippet of code to load your data from a XLS ( Excel
Workbook) file.
By default, the eXHelper uses the the cities.mdb or cities.accdb from C:\Program Files\Exontrol\ExCascadeTree\Sample\Access\.
In order to fix this problem you can do any of the following:
In case you have installed the x32 version of the component on a x64
machine, install the x64 version of the component as well, so the C:\Program
Files\Exontrol\ExCascadeTree\Sample\Access\ will be created automatically.
When installing the x32 version of the component the sample MDB and ACCDB
goes to C:\Program Files (x86)\Exontrol\ExCascadeTree\Access
Change the C:\Program Files\Exontrol\ExCascadeTree\Sample\Access\ path
with C:\Program Files (x86)\Exontrol\ExCascadeTree\Access or with your path
This error occurs when a not-bookmarkable ADO recordset is passed to the
control/view's DataSource property. In order to prevent that you have to check
the CursorType, LockType and Options parameter of the Open method (
recordset.Open ).
If case you are using a string DataSource, you can include any of the
following fields:
CursorType, determines the type of cursor that the provider should use when opening the Recordset.
If missing, the 3(adOpenStatic) value is used instead. The CursorType should
be one of the following numeric values, else an error occurs. Check the
Error event.
-1 (adOpenUnspecified) Does not specify the type of cursor.
0 (adOpenForwardOnly), Uses a forward-only cursor. Identical to a static cursor, except that you can only scroll forward through records. This improves performance when you need to make only one pass through a
Recordset.
1 (adOpenKeyset) Uses a keyset cursor. Like a dynamic cursor, except that you can't see records that other users add, although records that other users delete are inaccessible from your
Recordset. Data changes by other users are still visible.
2 (adOpenDynamic), Uses a dynamic cursor. Additions, changes, and deletions by other users are visible, and all types of movement through the Recordset are allowed, except for bookmarks, if the provider doesn't support them.
3 (adOpenStatic),Uses a static cursor, which is a static copy of a set of records that you can use to find data or generate reports. Additions, changes, or deletions by other users are not visible.
LockType, determines what type of locking (concurrency) the provider should use when opening the
Recordset. If missing, the 3(adLockOptimistic) value is used instead. The
LockType should be one of the following numeric values, else an error
occurs. Check the Error event.
-1 (adLockUnspecified) Does not specify a type of lock. For clones, the clone is created with the same lock type as the original.
1 (adLockReadOnly) Indicates read-only records. You cannot alter the data.
2 (adLockPessimistic), Indicates pessimistic locking, record by record. The provider does what is necessary to ensure successful editing of the records, usually by locking records at the data source immediately after editing.
3 (adLockOptimistic), Indicates optimistic locking, record by record. The provider uses optimistic locking, locking records only when you call the Update method.
Options, A Long value that indicates how the provider should evaluate the Source argument if it represents something other than a Command object, or that the Recordset should be restored from a file where it was previously saved.
If missing, the -1(adCmdUnspecified) value is used instead. The Options can be one or more CommandTypeEnum or ExecuteOptionEnum values, which can be combined with a bitwise OR operator.,
else an error occurs. Check the Error event.
ADO (OLEDB):
CascadeTree1.DataSource = "locktype=1;Source=C:\Program
Files\Exontrol\ExCascadeTree\Sample\Access\cities.accdb;Member=Select * FROM Countries;Key=CountryCode;Tag=Country;Name=CountryName >>> Member=Select * FROM States WHERE CountryCode IN (<%Parent.CountryCode%>);Key=StateCode;Name=StateName;Tag=State ||| Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.CountryCode%>);Tag=City;Name=Name >>> Member=Select * FROM Cities WHERE CountryCode IN (<%Parent.Parent.CountryCode%>) AND StateCode IN (<%Parent.StateCode%>);Tag=City;Name=Name"
or:
Set ado = CreateObject("ADODB.Recordset")
With ado
.Open "Countries","Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Program Files\Exontrol\ExCascadeTree\Sample\Access\cities.accdb",3,1,-1 ' adOpenStatic(3) adLockReadOnly(1)
End With
CascadeTree1.DefaultView().DataSource = ado
The View.Key property is empty or refers to a missing column in the current
view ( the view where you are selecting items ). If you are using the control's
DataSource property include the Key field in view's definition as explained here.
The Key property of the View object defines the index or the caption of the
column which defines the keys to create a new view once the user selects or
activates an item. At runtime, you can define the Key of the View using the Key
property of the View object.
The control provides a Name property to get / set the current path using the
Name columns of each view. In the same manner, the Name property defines the
name of the control on the form, so in order to prevent this confusion you need
to use the .Object.Name, instead of Name. The Object property returns
the original object.
Uses the MDB version of the database instead of ACCDB
Turn-off the DPI settings
You should know that this issue is not related to the control itself, it is
related to ACCDB files on non-DPI enviroments.
For instance, create a simple VB6 sample and run the code:
Private Sub Form_Load()
Set ado = CreateObject("ADODB.Recordset")
With ado
.Open "Countries", "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=C:\Program Files\Exontrol\ExCascadeTree\Sample\Access\cities.accdb", 3, 3
End With
End Sub
The same issue occurs, if the DPI setting is turned on.
When use generated code from eXHelper tool, please consider any of the
following suggestions:
General
The View(Tag) property returns the view object giving its Tag. In case no
view with specified Tag is found, it returns nothing, so no code can be
executed using the view. In order to prevent that just check if it is
Nothing, and if not continue. Currently, the eXHelper does not have any IF
clause, but we have plans adding support for IF statement.
Replace With .View("Country"), With
.View("State"), With .View("City"),
... with
Dim v As EXCASCADETREELibCtl.View
Set v = .View("State")
If Not v Is Nothing Then
With v
or add the On Error Resume Next command
If using the Name property of the control, you should use .Object.Name
instead to prevent confusion with Name property of the extended control (
Name of control on the Form ).
VFP ( Microsoft Visual Fox Pro )
The View(Tag) property returns the view object giving its Tag. In case no
view with specified Tag is found, it returns nothing, so no code can be
executed using the view. In order to prevent that just check if it is
Nothing, and if not continue. Currently, the eXHelper does not have any IF
clause, but we have plans adding support for IF statement.
Replace with .View("Country"), with
.View("State"), with .View("City"),
... with
IF ( !ISNULL(.View("State")) ) THEN
with .View("State")
Turn off the AutoYield property of the Application so VFP fires the events
The View(Tag) property returns the view object giving its Tag. In case no
view with specified Tag is found, it returns nothing, so no code can be
executed using the view. In order to prevent that just check if it is
Nothing, and if not continue. Currently, the eXHelper does not have any IF
clause, but we have plans adding support for IF statement.
Replace .get_View("Country"), .get_View("State"),
.get_View("City"),
... with
if( obj.get_View("State") != null )
Uses CtlSelect, CtlName
or CtlLayout instead Select, Name or Layout
The get_Background property returns a Color, while the set_Background
requires an uint, so you can use (uint)ColorTranslator.ToWin32
to convert a color to uint
The set_Background property requires an uint, and -1 is a signed integet,
so use unchecked((uint)-1) or UInteger.MaxValue