Category Archives: Foxpro

Writing tests for Business Objects in FoxPro

I’ve blogged before about converting my FoxPro apps from application forms to the Business Object based programming approach (thereby moving away from forms based heavily on open tables, work areas, and relations). I used the West Wind wwBusiness classes to make this transformation, and it is the most exciting VFP work I have ever done. A Business Object framework like West Wind wwBusiness automatically gives you basic niceties such as methods like Load() and Save() right there on the BO to do all the back end data handling for you. This feature alone allowed me to greatly reduce the amount of code I had piled up in click events all over my *forms* for many years. No more worrying about the the record pointers, or relations, or binding my form UI controls directly to table names and fields. I promise you, once you go BO’s you’ll never go Back!  (Don’t get sidetracked from this post yet, but you can read my original review of the West Wind wwBusiness library here.

Another benefit of BO classes is that you can now programmatically drive your application’s activities by making method calls into the various methods on the BO. No UI forms required… Just good old procedural code! For instance, on my Job Business Object, I have lots of methods to fetch records into a local cursor, array, or collection, as well as other methods that change or examine data on the BO, or return scalar values, etc.  I started out forcing myself to  test my BO’s from the command line to make sure I could manually orchestrate everything I wanted my forms to do. This would ensure that it would require very little code in the UI forms to make the app work. With all the essential code tucked away in methods on BO classes you can then basically create the same app in SCX Forms, or web frameworks, or just good old procedural programming in various PRGs. Plus, the ease of maintenance improves greatly, since all your code lives in one class, rather that splashed all over the place inside a form.

So I’ve had this vision, after hearing more and more about all this “Test First” buzz in other coding circles like .Net and Rails, that I could write a suite of PRGs that serve as tests I can run at any time on my entire collection of BO’s. This allows me to immediately test every BO in my library any time I make code changes anywhere in the class hierarchy, or even if the table schemas changed too. I can’t tell you how many times I’ve made low level changes in the base classes, or added a new top level method to a concrete class, or changed a field name in a table, and the only real way I’ve had to test the changes is to throw out a beta version of the app, and drive it around like a real user to see if it works correctly, or has errors.

 

Here is a peek at one of my Business Objects; the “Job” Business Object which is a vital part of many forms in my app. There are perhaps 20 or more granular methods that can be called to do all kinds of fancy stuff on a Job in our system.

Every method  can be called directly from the Command Window, or from methods in forms, or from within PRGs. Just create an instance of the Job object, and off you go. Most of this code once lived in a SCX form somewhere, until I pulled it all out and put it in this Job Business Object.

image

And shown below is a sample of the test code I have written which creates a Job Business Object, and then tests a particular method (the GetActiveJobs() method in this example). You’ll see in the comment that this method can accept up to 5 parameters, so I’ve written tests for many possible combinations of parameters and values. Even with this many test calls, I’m sure there are a few combinations that I may have missed. This shows how tedious a full test suite can become. In this testing approach, you basically *TRY* to break your code by passing in every possible combination of parameters that these business classes might see in real application usage. Remember, you want to write these classes with the idea that you or someone on your team will be working with these classes for years, you simply expect them to work without knowing all the do’s and don’ts about calling into these methods.

SNAGHTML19918d5

What you don’t see here is that the test method calls likes BeginningOfTest(), TestProgress(), and EndOfTest(), record logging info to a results file that I can then review to study the return values, processing time, etc.

Now, the bad thing is that if I complete this exercise, there are perhaps 20 or more methods that I must write tests for, and that’s just on the Job Business Object. Then I’ll have to tackle all the other Business Objects in my libraries (PurchaseOrder object, Quote object, Part object, etc. About 15 Business Objects in all). So this is no trivial amount of work, and you have to remember to write a test for every new method you add to a Business Object, otherwise, you’re letting the thing fall apart. It’s very easy to look at your code and think you’ve got everything or every situation covered, but certainly creating a formal test suite for your classes will help identify problems before you take your app to production. Oh, you’ll also notice that CreateWWBO() is a factory method that returns a Business Object based on the passed key, so there’s some other coding in my architecture that resolves this tag and the class name as well as the class library.

And here is the output to the log file. If there were any errors returned from the Business Object, or if the return results were not the expected results, then I’d see reporting to this effect in the log file. Now, there is some coupling here between these tests and test data that I’m running against, so the test could appear to break if some of the test data changed, so this is no magical solution and requires some attention to this detail when preparing and running these tests. To me, the main effort is to find broken code in the classes given a predictable data set.

image

 

This is just one code sample. I have other tests that test the basic Load(), New(), Save(), and Delete() methods as well.

 

By the way, you can read my original review of the West Wind wwBusiness library here

Extracting Enum values from an assembly file using the Object Browser in FoxPro

Thanks to a helpful comment from Doug Hennig, I’ve learned how to use the Object Browser in Foxpro to extract Enum values from an assembly file right into a .h file inside of FoxPro.  By an “assembly”, I mean a dll file that is installed on your machine when you install software or API tools to communicate with various software packages.

For instance, here is the Object Browser in FoxPro taking a peek inside a dll assembly from the QuickBooks SDK ver 10:

SNAGHTML3ea8bd

I posted an article recently about communicating with QuickBooks from FoxPro, where I explained some problems I began having with the .h include file I was using, which had become out of date when we upgraded to the latest version of the QuickBooks SDK. You can see that post here if you’re interested in the original problem I was having: http://mattslay.com/adding-custom-data-to-quickbooks-invoices-from-foxpro/

The problem was that I needed the latest Enum values (“constants” in FoxPro) from the new assembly that came with the QB SDK ver 10. The Enums from a dll are exposed nicely when programming inside Visual Studio, but there is no FoxPro .h include file included in the QuickBooks SDK for us Fox programmers. I knew the information I needed to create a FoxPro .h file was hidden away in that .dll somewhere, I just didn’t know how to get them out of there in an automated fashion. In the original post linked above, I showed where I was able to see them inside of Visual Studio, and even determine the values of each one, but it was a very manual process. I was sure there was a better way. And there was. It was super-smart FoxPro MVP Doug Hennig who showed me the way, using the Object Browser in FoxPro.

So, with a little expansion on Doug’s original hint, I was eventually able to drag-and-drop the  entire Enum node from that QB assembly file right into a code file in FoxPro to get a full list of constants nicely defined and formatted in a .h include file.

It turns out that the Object Browser in FoxPro has some pretty good (but not perfect) support for this… It was close, but not exactly what I needed, since it required a LOT of manual drag-and-drop maneuvers. So I Googled around and stumbled upon the golden nugget that I needed to completely solved the problem to my liking. To dig into the solution I found, you can check it out here: http://www.dbmonster.com/Uwe/Forum.aspx/foxpro/7047/Utility-to-extract-print-all-enumerations. I am not going to repeat all the code and discussion from that thread in this post, just to avoid redundancy. There’s a lot to be learned from reading the thread yourself if you want to dig into the details, but that’s not necessary unless you want to explore the issue deeper. In short, I followed the thread and picked out the various instructions and was able to have it all working in just a few minutes.  So, to make it easy for everyone else, you can skip all the details in that post and just download the enhanced version of the Object Browser from the links below. Or, If you want to dig deeper into the code yourself, I’ve given you the steps you’ll need to follow to make the modifications yourself….

Instructions to modify the Object Browser for Enum Extraction

Fortunately, the source code for many of the FoxPro tools like the Object Browser were release to the community a few year ago so we could enhance them and keep the tools current.  That’s what the guys in the dbmonster post did to solve this problem (link below), and I’ve wrapped it all up here in an easy download file to share it with you:

Option 1 – Download the modified file from my site and start using it now:

If you do not want to modify the code yourself, you can download the .exe file that I built from here: http://mattslay.com/download-files/object-browser-modified-for-enums.exe

If you want a copy of the modified source code, you can download the whole project here: http://mattslay.com/download-files/object-browser-modified-for-enums.zip

Option 2 – Do it yourself – To update the FoxPro Object Browser yourself with this expanded functionality, follow these steps…

1. Go to the VFPX site and download the Xsource code here: http://vfpx.codeplex.com/wikipage?title=XSource. Extract the ‘obrowser’ tool from the zip and open the project file in VFP.

2. Make these changes to the source code… (follow the discussion and see the code at this link: http://www.dbmonster.com/Uwe/Forum.aspx/foxpro/7047/Utility-to-extract-print-all-enumerations

3. Next, compile the project to an .exe (name and location is your choice).

4. Now you can run your new version of the Object Browser to accomplish this task and output shown above.

Results

Here’s the beautiful output you’ve been waiting to see.  (Note: I manually added the top few lines of comments to record some notes about how the files was created and what version is.)

By the way, if you happen to need the complete QBFC10Lib.h file that I’ve extracted for with FoxPro, you can download  it here: http://mattslay.com/download-files/QBFC10Lib.h   If you’re working with a different version of the QB SDK, then you should extract the Enums yourself from the correct dll from your version of the SDK, and build your own .h file.

*** FoxPro constants from QuickBooks SDK assembly QBFC10Lib
***
*** To see the origin of this file, visit this link:
***   http://mattslay.com/adding-custom-data-to-quickbooks-invoices-from-foxpro/
***
**********************************************************************************

*— Constant Group: ENOpenMode
#DEFINE omSingleUser    0   
#DEFINE omMultiUser    1   
#DEFINE omDontCare    2   

*— Constant Group: ENRqOnError
#DEFINE roeStop    0   
#DEFINE roeContinue    1   
#DEFINE roeRollback    2   

*— Constant Group: ENReleaseLevel
#DEFINE rlPreAlpha    0   
#DEFINE rlAlpha    1   
#DEFINE rlBeta    2   
#DEFINE rlRelease    3   

*— Constant Group: ENRqResponseData
#DEFINE rdIncludeAll    0   
#DEFINE rdIncludeNone    1   

…etc…

Enjoy!

Adding custom data to QuickBooks invoices from FoxPro

I finally figured out a bug in my VFP code that we use to add data to custom fields in QuickBooks invoices!!!!

Well, actually, it turns out that there was no a bug in *my* code at all… The bug (so to say) was in the qbfc.h constants file that I had used successfully for years to do this very task. However, apparently when I upgraded to QuickBooks 8.0, the Enumeration values for the various QuickBooks object types changed from what they were in the previous version, for which my qbfc.h file had worked just fine.

When programming QuicjkBooks with the QuickBooks SDK, you use various constants to describe what objects, actions, or transactions you want to create or edit. So, the best way to deal with this pattern in programming languages is to assign Enums for each value, which makes your code much easier to read, and modify; you see words rather than numbers, and, should the Enum values change, your code that uses the Enums will still work. However, it *is* important/necessary to update the Enum values to match the API of whatever you are programming against. Duh! So, in C#, the Enums and values live in a namespace and a dll file that you get with the SDK. But, In FoxPro, you have to build your own .h file to define and manage “constants”, which are basically used in the same way as Enums in C#.

The original qbfc.h file that I have came from a guy named Cris Musgrave. I found it somewhere on the internet several years ago. (Thanks, Cris.) The file had dozens of constant names and values assigned. I sure wish I new where Cris got these values, as it appears to be generated from some other source. Surely, he did not type in all the values himself!  Also, it was from 2004, and work great with QB 2004, and so on, until I got to QB8.0. That’s when it quit (a couple of years ago, and I just now got motivated to find the problem!) I’ve tried to find out how to reach him, but I’ve had no luck. (Hey, Cris, give me a shout some time, please.)

So, it turns out the problem was simply that the constants from the qbfc.h file no longer match the integer values for QB8.0. Easy to fix, if I just can learn what the new values are. Well, I’ve looked all of the Google, and I cannot find such info. If you know where to find this valuable info, please let me know.

Here’s the VFP code that sets the object type when you are goinf to add/modify a custom data field on an existing invoice:

loDataExtMod.ORListTxn.TxnDataExt.TxnDataExtType.Setvalue(tdetInvoice)

So, in the above method call, the “tdetInvoice” is a reference to a constant value from the qbfc.h file, which was defined as 11, but as of QB8.0, I’ve learned that the actual value for the “tdetInvoice” object is 13!!! (See below to learn how I figured this out.) Obviously, I can now see that these values are subject to change with any given release of QuickBooks, so watch out. I sure will.

Here’s a peek at the qbfc.h file I use with FoxPro:

image

 

In fact, I’ll bet many/most of the values are now wrong when used with QB8.0.  I need the correct values!!!

 

Problem Solved

Here’s how I figured out that the correct value for the constant/Enum “tdetInvoice”:

I downloaded a sample C# app a QBFC sample from the Intuit web site, and I opened the Solution file in Visual Studio. I could see in the references that it includes a reference to QBFC10.dll, so I used the Object Browser to peek inside the QBFC10.dll assembly to see the namespaces and Enum classes, and after some snooping around, I found the golden info that I needed:

image

 

Then, I wrote a line of code to see what value I got when I referenced this constant:

clip_image004

 

And, the Watch window in Visual studio will show you the value of a variable:

clip_image006

 

So, this is a long, slow process, but I have now corrected my qbfc.h file, and my code is working again!!! I suspect there are other changes to, but I only use a small set of them, so, for now, my code works fine. I’d love to know how to extract all the Enum names and values from a dll so I could generate a full, accurate qbfc.f file.  Anyone know how to do this?

Object Inspectors and Explorers for FoxPro

An “object explorer” or “object inspector” is a visual tool that provides a GUI mechanism to explore and navigate the hierarchy of a saturated FoxPro object. This allows you to see all the property names and values that live on an object, and any nested hierarchy that is often present on complex objects like Business Objects.

In my studies of this type of tool, I have come across three available choices. If you know more, please leave a comment, and I’ll add them to the article so that we can have a complete list.

Three tools are reviewed in this article:

  • Mike Feltmans’ Collection Explorer
  • CodeMine Object Explorer
  • Tamar Granor’s Object Inspector (coming soon)

Mike Feltman’s Collection Explorer

At SWFox 2008, I saw Mike Feltman present a session on FoxPro Collections, and in that session he briefly showed what he appeared to regard as an incidental tool he had developed, which he called “Collection Explorer”. Even though it has “Collection” in the name, it actually works on ANY FoxPro object, so I quickly used this tool to take a peek at one of my relatively complex West Wind wwBusiness business objects:

I became really interested in this tool, and instantly added it to my FoxPro IDE toolbox (after bugging Mike for a few weeks to release the final version which he promised in his session). I even integrated it into my production app as a way to allow advanced users to dig around in ways that were not provided in the main forms of my app.

CodeMine Object Inspector

In my typical fashion, I also began to dig around and stir the pot in the community about this problem space, and somehow that lead me to another tool called the CodeMine Object Inspector.  You can download it from here: http://www.codemine.com/ (under the Free Developer Tools). The source files are dated 1999, which is kind of old, but it seemed to work fine in my initial tests in VFP 9 SP2.  Here is a screenshot:

I have not used it extensively, but at first glance, it seems to cover all the basics that the other tools do.

Tamar Granor’s Object Inspector

Sadly, I did not attend the SWFox 2010 conference after having made my first SWFox conference in 2008, and again in 2009. I first heard about Tamar’s Object Inspector from Jim Nelson, the author of PEM Editor on VFPx, who was at the 2010 conference. We spoke daily during the conference so I was able to keep close tabs on everything.  One of the updates he gave me was that Tamar Granor made reference to an “Object Explorer” tool that she was developing. Following the conference I asked her about it on UT, and sure enough, I eventually saw it for the first time in November 2010. In mid-December 2010 she released a second iteration to a small group for testing and feedback. 

There will be an article on the Object Inspector in the January 2011 edition of FoxRockX.

Release plans: She has stated that her plan is to submit the Object Inspector to VFPx. I don’t know what her expected timeline for release is, but I’ll keep you updated as I know more about it.

Here is a screenshot:

 

wwBusinessPro – Article 2: Configuring Child classes (wwBusProItemList)

Note: This post if part of a complete series on the West Wind wwBusiness library.
Click here to see the full index

Another enhancement I added to wwBusinessPro was to allow for Child record collections to be easily used with a Parent BO.

When using a wwBusProParent, you set a few properties on the Parent that tell it about the Child class. Then, the Parent will create the Child class for you. So, when you’re working with your BO’s in code (after everything is all configured), you do not create the Child, you let the Parent do that. You will create a VCX library and add a Child class for each Child collection in there (based on wwBusProItemList), with its Child properties already set up. This allows the Parent to create the Child when he needs it. So you can see how this works, if you were to follow the path of the Get() method (remember, this is a key extension method I added in wwBusProParent), you will see that the Parent creates the Child object and attaches it to its oLineItems property. So, once your Child classes are configured in a VCX, you will not actually have to write any code to access them (unless you are doing some special case, custom coding), you just set up the Parent so he can find them. The Parent will handle all that for you, including the fetching of the related Child records.

Code Sample: Creating and using your first Parent Business Object

Parent Setup:

When using a wwBusProParent, you set properties on the Parent that tell it about the Child class.
Then, the Parent will create the Child class for you.
You do not create the Child when writing your code, let the Parent do that.

You need to create a VCX library and put a Child class for each Child collection in there,
with its Child properties already set up. This allows the Parent to create the Child when he
needs it. If you follow the path of the Get() method, you will see that the Parent creates a
Child class object and attaches it to its oLineItems property. So, once your Child classes are
configured in a VCX, you will not actually have to write any code to access them (unless you are
doing some special case, custom coding), you just set up the Parent so he can find them.
The Parent will handle all that for you, including the fetching of the related Child records.

You can also put your Parent objects in the VCX and set their properties in the VCX file.
This sample code is shown here simply to show which properties are required to make it all work.

Child Setup

When setting up your Child in the VCX, these are the properties you need to set on it:

cFilename (Required. Name of the dbf or Sql Server table)
cAlias (Optional. Will use cFilename by default)
cPKField (Must be an Integer. See “Important Note” below)
cFKField (Must be an Integer. Maps to Parents PK field)
cLookupField (Optional. Maps to Parents cLookupField. Use when Parent uses for String lookups)
cOrderFld (Optional. Can be used to set the ordering of child records. i.e. a sequnce field)

These properties provide the info needed by the LoadLineItems() method work out of the box.
Sometimes you may want to overwrite the LoadLineItems() method with custom code, but the default
should work in basic configurations.

IMPORTANT NOTE:
In order to save changes on the Child records, they need a unique PK that can be used. See cPKField.
String cLookupField works fine to load the records in, but it does not guarantee uniqueness when
trying to save changes back.

Again, you can use cLookupField Stings for loading the records, but you must have Integer PKs
on your Child records to allow saving changes back.

wwBusinessPro – Article 1: String Lookups

Note: This post if part of a complete series on the West Wind wwBusiness library.
 

I’ve written an extension library on top of the West Wind wwBusiness classes. You can read the original post on my work here.  In my enhanced library, which I’ve named wwBusinessPro!, one of the things I’ve added is a lookup method that will handle String ID lookup values in addition to the native handling of Integer PK’s. The base wwBusiness library only works with Integer PK lookups, and I needed an enhancement to work with String lookups to get started with wwBusiness in my app.

When using my wwBusinessPro class, the main method that you call to do a lookup is the Get() method. You will call this method even when doing a Integer PK lookup because it will expose all the other extensions I’ve added to the library (more on that later).

So, the Get() method accepts one parameter which can be an Integer or a String.

    oJob.Get(123) && An Integer PK lookup

     – Or –

    oJob.Get(‘123’) && A String lookup

Now, on each Business Object class that you create, you need to specify the following properties to allow any kind of lookup to work. (This is how the base wwBusiness functions, so this is not a new feature in wwBusinessPro!, except that I have extended it to work with String values too). The cPKField setting is required for all cases, and cLookupField is only required for String-based key values, in which case you must specify the same column names for both properties.

cPKField (This property is required. Choose either and Integer Pk column or a String key value column)

For Integer PK’s set this value to the name of the Integer PK column in the table. (basic wwBusiness feature)

For String PK’s set this value to the name of the String key value column in the table. (new feature)

Note: this key value is what will be used to locate your record when saving changes to existing records. For String key values, be sure you do not use Set Exact Off or else you may update the wrong record based on a partial string match.

cLookupField (optional)

Leave blank if you do not have a String value lookup field. (This is an extension property that I added to handle String lookups.)

For example, in an oJob class, you would set the cLookupField to the name of the column that has the string lookup key in it. For my Job table, the cLookupField property is set to ‘job_num’ which is a string column. Now it knows to look for the string value ‘123’ in the ‘job_num’ column. I also have Integer PK’s on that same table, so I also set the cPKField property to ‘ipkey’. Now my processing can also be done by the PK Integer value, if I know it. So I can now do lookups either by Strings or Integer PKs.

How it works:

The Get() method will determine what kind of lookup you are trying to do based on the data type of the value you pass in (integer or string) and will make the correct method call to other methods to do the actual lookup, all of which eventually drill down into the base wwBusiness class to do the lookup. Just pass in a string or an integer and it will happen like magic. You can then check the oJob.lFound property to determine if the requested record was found.

Here’s the code for the Get() method:

image

 

More about string lookups:

For string lookups, if you need more flexibility on the cLookupField, you can bypass the Get() method and use a lower-level lookup that accepts an alternate lookup column. It’s called LoadByRef() and accepts a string lookup value and a column name in which to perform the lookup. Like this:

oJob.LoadByRef(‘53443’, ‘po_num’) && Load a job by the po number.

And, to take it one step further, there is one more way you can further control the lookup, and that is by setting a property called cAdditionalFilter. Rather than accepting it as a parameter into the LoadByRef() method, it works as a property that you set before calling the method. This powerful feature allows, for example, find the first record with Status=”A” for Customer “DEN001”. You will just have to be creative and explore all the ways this method can be used. For DBF mode, the base wwBusiness method uses the LOCATE command, so the lookup is from the top down, so it will find the first record. For Sql Server mode, you can even include an Order By clause at the end of the cAddtionalFilter to all effectively working from the bottom up.

Example:

    oJob.cAdditonalFilter = ‘Status = [A]’
    oJob.LoadByRef(‘DEN001’, ‘cust_num’)

You can use any complex expression you want to in the cAdditionalFilter property:

    oJob.cAdditonalFilter = ‘Status = [A] and Amount>1000’

Remember, in my methods, I am still eventually using the base wwBusiness methods to do the work, it’s just that I have built a wrapper around it to make it easier to use.

Here’s the method code for LoadByRef()

image

 

 

Note: This post if part of a complete series on the West Wind wwBusiness library.

Exploring my wwBusiness extension library

Updated 02/01/2010 1:26 pm

I’ve written an extension library on top of the West Wind wwBusiness classes for object oriented data access in Visual FoxPro, which I’ve named wwBusinessPro. In this blog series I will explain some of the basics about the base West Wind wwBusiness data access library and my extension library wwBusinessPro, which is built on top of it.

You can read the wiki pages  and download the wwBusinessPro library from the BitBucket repository.

I’ve prepared several articles explaining some basics of the main wwBusiness library from West-Wind Technologies and how my wwBusinessPro extension library adds support for String lookups and Parent-Child data models for your applications.

It’s not hard to get started… I recommend this strategy:

1. Before you try to jump in, take time to read each article listed below.

2. When you are ready to start, follow the instructions in the post Setting up wwBusinessPro.vcx to work with wwBusiness.vcx

3. Now create a new class library for your Business Objects and add a Parent BO class inherited from wwBusProParent, and one or more Child BO classes (ones that are related to the Parent you created) which inherit from the wwBusProItemList class.

4. Next, add data rows to the wwBusinessObjects.dbf table to setup your Parent and Child business objects. (see wiki page for screenshot). There will be one row for the Parent, and a row for each Child that relates to the Parent.

Now you’re ready to go… With a Parent and a Child BO properly configured, you can actually drive the whole thing from the Command Window, which is a good way to play around with it and see it work. See this code sample for a typical code snippet that is used to work with BO’s. After a little testing you’ll be ready to create (or modify) your forms to use the Parent/Child BO pair. It’s not all that hard, you just need a simple get-started case to help you see it all come together.

Articles

Intro and overview articles:

Read my original review of the West Wind wwBusiness library here 

Article 1 – String Lookup enhancements in wwBusinessPro

Article 2 – Parent-Child enhancements in wwBusinessPro

 

Specific Steps to use wwBusinessPro BOs in your code and forms:

Step 1 – Setting up wwBusinessPro.vcx to work with wwBusiness.vcx

Step 2 – Creating and using your first Parent Business Object (wwBusProParent class)

            (also see this Help entry from the base wwBusniess Help File)

Step 3 – Setting up Child cursors with Parent BOs

           (also see this Help page from the base wwBusiness Help File)

 

Other wwBusiness resources:

Main wwBusiness Help File from West Wind (click Class Reference –> Class wwBusiness)

Article by Kevin Cully about wwBusiness (PDF)

 

Licensing:

wwBusinessPro is a free open-source project, but you’ll need to purchase your own license for the main wwBusiness library from West Wind.  It is included as part of the West Wind Web Connection package and  also included in the West Wind Client Tools package at the West Wind web site.

 

If you have any questions or need specific help please comment below.

Grid Column DataBinding feature for VFP Grids

I want to share some code from my custom grid class that creates an easy way to programmatically bind columns in a grid to a cursor that is opened in the workspace. Basically, this method binds each column’s ControlSource property to the field in the cursor that you specify. It  also handles calculated fields, Casting, and a few more things I’ll show in the code samples below.

You do have a custom grid class that you use in your apps, right? So, now just do two things to your grid class:

  • Create a new placeholder method on your grid class named SetColumnControlSources().
  • Create a new method named BindColumn() and add my code from the BindColumn() code sample below.

Now, in each instance of the grid that you use on a form or class or subclass, create the required columns on the grid and set the header captions to match what you intend to show in the grid from the cursor. Be sure to give each column a smart Name property for easy coding (see example below). You do not set the ControlSource of each column while designing the grid. That’s what my fancy BindColumn() method does for you, along with a few more things you’ll see in the code sample. You will make calls to the BindColumn() method from your SetColumnControlSources() method to do the real work. I’ll show you how…

In the SetColumnControlSources() method of each grid instance, you’ll write code like this (specific to each grid<—>cursor matching that you want to build):

Sample SetColumnControlSources() method code:

Local lcRecordSource

With this
.BindColumn(.colItem, ‘item’)
.BindColumn(.colPrint, ‘print’)
.BindColumn(.colPartNo, ‘part_no’)
.BindColumn(.colAltPartNo, ‘altpartno’)
.BindColumn(.colDwgNo, ‘dwg_no’)
.BindColumn(.colDesc, ‘desc’)
.BindColumn(.colQty, ‘qty’)
.BindColumn(.colPrice, ‘price’)
.BindColumn(.colTotal, ‘qty * _RecordSource.price’)
.BindColumn(.colLaborCost, ‘laborcost’)
.BindColumn(.colLaborHrs, ‘laborhrs’)
.BindColumn(.colMachRate, ‘laborcost / _RecordSource.laborhrs’, ‘N(10,2)’)
.BindColumn(.colMtlCost, ‘mtlcost’)
.BindColumn(.colMtlMarkup, ‘mtlmarkup’)
.BindColumn(.colPartCost, ‘laborcost + _RecordSource.mtlcost + _RecordSource.mtlmarkup’)
.BindColumn(.colTotalCost, ‘qty * (_RecordSource.laborcost + _RecordSource.mtlcost + _RecordSource.mtlmarkup)’)
EndWith

*– Other fancy stuff you can do in addition to the above —

lcRecordSource = this.RecordSource

If !Empty(this.RecordSource)
this.colItem.DynamicFontUnderline = ‘iif(‘ + lcRecordSource + ‘.divider=.t., .t., .f.)’
this.colprice.DynamicCurrentControl = ‘iif(‘ + lcRecordSource + ‘.no_quote, [lblNoQuote], [Text1])’
EndIf

Notice how we can build calculated columns that are not even in the cursor, and easily setup a Cast() to control decimals and some DynamicXXX formatting too. Plus, it gives me one nice code window to see all my column binding without having to use the Property Sheet to see what each column is bound to.

So the above is *your* code, and now here’s *my* custom BindColumn() method code that you need to add to your grid class to handle the code you’ll write like the above. This methods assigns the Column.ControlSource property, expanding any _RecordSource references, and also handles the optional Cast() function (see code for .colMachRate above to see how to specify a Cast() format in the third parameter of the BindColumn method).

BindColumn() method code:

Procedure BindColumn()  (Add this method to your grid class)

Lparameters toColumn, tcBindExpression, tcCast

Local lcFieldExpression, lcBindExpression, lcRecordsource

If Vartype(toColumn) = ‘O’ and Upper(toColumn.baseclass) = ‘COLUMN’
lcRecordsource = toColumn.parent.RecordSource

If !Empty(lcRecordsource) and !Empty(tcBindExpression)
  lcFieldExpression = Alltrim(Strtran(Upper(tcBindExpression), ‘_RECORDSOURCE’, lcRecordSource))

  *– Combine RecordSource.FieldExpressiopn
  lcBindExpression = lcRecordSource + ‘.’ + lcFieldExpression

  *– Wrap in Cast() statement if casting was passed in
  If Vartype(tcCast) = ‘C’
   lcBindExpression = ‘Cast(‘ + lcBindExpression + ‘ as ‘ + tcCast + ‘)’
  EndIf

  *– Finally, set controlsource on column…
  toColumn.ControlSource = lcBindExpression
EndIf

Else

Return

EndIf

Finally, to make it all work, you simply set the RecordSource property on the grid and then call SetColumnControlSources():

thisform.Grid1.RecordSource = ‘csrDataCursor’

thisform.Grid1.SetColumnControSources()

 

I found having this in place to be an effective way to handle times when I need to kill the cursor, rebuild it, and then re-bind to it.

Like this:

thisform.Grid1.RecordSource = ‘’

*—Now rebuild the cursor

thisform.Grid1.RecordSource = ‘csrDataCursor’

thisform.Grid1.SetColumnControSources()

 

So there you go. Several tricks could be used to pass in the cursor field that you want to bind to.  I’ve also thought about including a provision for passing in the Header caption too.

Enjoy, revise, and post comments to share any other ideas you have for extending this.

To Blog or to Forum Post, that’s the question…

I’m not really sure why I’m so driven to do this, but I’ve always been a spread-the-news kind of guy for the VFP community. Any time I see something cool, or that I think others may be interest in, I make a post here-and-there to all the most popular FoxPro sites to spread the word.  So, about a month ago I cranked up this blog for the purpose of doing just that, thinking this would be a good way to go.  Now, I don’t want to compete with the existing forums, because it’s easy enough to go there and make announcements, but I have to visit UniversalThread, and  Foxite, and the ProFox and VFUG lists too, oh, and even Fox.Wikis.com, oh, and sometimes use my FoxCentral.net account. I usually have to hit all those sites with a bunch of cut-and-paste to work all the places I want to reach. Plus, after posting to forums and lists, if I need to tweak the info (corrections, add details, etc), it’s too late to edit or just too much work. And, any conversations (comments) about the topic are now spread out across all the different places and there’s no one place other readers can visit to take it all in. Plus, the formatting and image posting in a blog is much better.

So, I’m trying to decide whether it really adds any value to put this info in a blog post and try to get an audience following the blog, or just keep it old school and post in multiple places.

Your opinions please.