One of the nice things about Visual Studio .NET is that with each release we get more and more great user interface components, and what’s even better is that with .NET you can use most of these directly in your applications. Take the PropertyGrid control, this provides a user interface for browsing the properties of an object and is used everywhere in Visual Studio by Microsoft which is a tribute to its out-of-the-box functionality. Now we all know that Visual FoxPro is a great product but it does tend to get left behind in the user-interface assets department which can be a bit frustrating. Even with VFP 9 which includes some fantastic enhancements such as dockable forms, control anchoring etc. it still requires some assistance to give it the latest-greatest look.
If we go back to the .NET PropertyGrid example I am sure there are dozens of instances you can think of where this control would have solved lots of problems in your FoxPro user interfaces. By design the control is hierarchical, sharing a lot of common ground with the classic Win32 TreeView, the PropertyGrid takes that one step further by allowing you to categorise your data in a hierarchy or show it flattened and sorted. Data entry can be controlled through pre-defined selection lists or by the use of more specialised popup editors such as a directory browser or font selector. So how can we bring this control to our VFP applications? Well there are still a lot of component vendors out there writing high quality ActiveX components which integrate well into Visual FoxPro, one such vendor is CodeJock Software who offer the reasonably priced Xtreme Property Grid that can be incorporated directly into your FoxPro applications.
http://www.codejock.com/products/propertygrid/activex/
All the Fox diehards will be happy to see Visual FoxPro listed on there and they even provide a Visual FoxPro example for educational purposes. Using the component is easy and if you have ever done any work with the TreeView ActiveX then this will be very familiar territory. The client area of the component contains 3 key elements.
- Toolbar
- Hierarchical Grid
- Help Pane
If you go over to the gallery portion of this blog you can see a screen shot of one of our Microsoft Navision utilities with a pre-loaded instance of the property grid control.
http://weblogs.foxite.com/neiltonkin/gallery/image/18.aspx
The Toolbar contains two buttons that when clicked will change between the two views; this can be toggled on or off using the ToolBarVisible property. When setting up the remainder of the control there are a number of key tasks you need to do including setting the height of the help pane in pixels and also the ratio of the split in the grid between node prompts and the associated data.
with ThisForm.olePropertyGrid
*!* Display the toolbar.
.ToolBarVisible = .T.
*!* Display the help pane and set its initial size
*!* in pixels.
.HelpVisible = .T.
.HelpHeight = 78
*!* Set the grid splitter proportion as a percentage.
.SplitterPos = 0.35
*!* Set the visual theme.
.VisualTheme = 0
endwith
The control also allows you to select one or more Visual Styles or Themes by setting the VisualTheme property to one of the following enumerations.
#DEFINE xtpGridThemeDefault 0
#DEFINE xtpGridThemeNativeWinXP 1
#DEFINE xtpGridThemeOffice2003 2
#DEFINE xtpGridThemeCool 3
#DEFINE xtpGridThemeSimple 4
#DEFINE xtpGridThemeDelphi 5
A good tip for getting these values from the type library is to use the Object Browser that comes with Visual FoxPro. Load the OCX control into the Browser and expand the Enums node then drag and drop the desired enumeration (in our case the XTPPropertyGridVisualTheme node) into the command window or any code editor will produce the definitions above.
Loading the control is quite straight forward; you need to work out in advance the categories for your properties or drive its construction from data – it’s entirely up to you.
with ThisForm.oleProperties
*!* Clear the categories collection.
.Categories.Clear()
*!* Add a new category and make sure it is expanded.
loSection = .AddCategory("(Identity)")
loSection.Expanded = .T.
*!* This is the desription that will appear in the
*!* help pane.
loSection.Description = "Connection Type"
endwith
Before you can add properties to our new section through the loSection reference you must get the PropertyItemType enumeration from the type library, this is used to define the type of data that will be maintained and can be one of the following.
#DEFINE PropertyItemString 0 && String Item
#DEFINE PropertyItemNumber 1 && Number Item
#DEFINE PropertyItemBool 2 && Bool Item
#DEFINE PropertyItemColor 3 && Color Item
#DEFINE PropertyItemFont 4 && Font Item
#DEFINE PropertyItemDouble 5 && Double Item
#DEFINE PropertyItemDate 6 && Date Item
#DEFINE PropertyItemPicture 7 && Picture Item
As you can see there is default support for the most common types including complex data types such as pictures/images.
with ThisForm.olePropertyGrid
*!* Add a read-only string property called Driver with its value
*!* taken from a field in the odbcconnections table.
loPropertyItem = loSection.AddChildItem(PropertyItemString, ;
"Driver", ;
alltrim(odbcconnections.driver))
loPropertyItem.ReadOnly = .T.
*!* This is the description that will appear in the
*!* help pane.
loPropertyItem.Description = "The ODBC driver used as the " + ;
"basis for the connection."
endwith
Now the cool thing about the PropertyGrid controls object hierarchy is that once we have a reference to our new property we can call its AddChildItem method to add a sub/child property in a hierarchical fashion beneath it in exactly the same manner as above.
http://weblogs.foxite.com/neiltonkin/gallery/image/20.aspx
In the previous example we made our property read-only but more often than not you will need to know when a user has changed a value of one or more of your properties. To do this you need to assign a tag to your property item and then place code in the controls ValueChanged event. The Tag property is not like the one exposed by the TreeView, it’s a long/numeric value not a string which if you did what I initially did which is NOT to RTFM then you get errors.
loPropertyItem.Tag = 1000
Now put some code into the ValueChanged event to handle the user changing the property content.
*** ActiveX Control Event ***
LPARAMETERS item
if item.Tag = 1000
MessageBox(item.Value)
endif
One of the things that can happen when loading a lot of information into the grid is flickering of the scroll bar. We can stop this happening using an old trick involving the LockWindowUpdate Platform API function.
declare short LockWindowUpdate in WIN32API integer hWnd
= LockWindowUpdate(ThisForm. olePropertyGrid.hWnd)
Calling this before you start loading the control with properties can stop this annoying update artefact but remember to issue the corresponding unlock or your control will not update itself.
= LockWindowUpdate(0)
Hopefully this will help you with the basics of this control; in my next entry I will show you how to define your own editors for tasks like directory selection.