Passing Property Bags

Team-Fly

I attended one of Francesco Balena's (fbalena@softdes.it) talks at VBits in the fall of 1999. He discussed a number of ways to improve performance in Visual Basic applications, which was very enlightening. Many of his suggestions are incorporated in this chapter and others. After his talk, I cornered him to get his opinion on the fastest way to pass data between tiers. I suggested user-defined types and delimited strings. He listened patiently like one of those mountaintop monks. He then proceeded to describe a fairly obscure (to me) technique—PropertyBag objects. While I knew that these were not sacks kept backstage at a burlesque theater, I had never used them (intentionally). He told me that the PropertyBag was implemented for the first time in Visual Basic 5.0 and improved in Visual Basic 6.0 to support "persistable" objects by exposing the Persistable class attribute.

Basically, a PropertyBag is an object that can work as a repository for any type of (simple) data, which includes all public creatable numeric and string data, but does not include arrays and collections. This means that you have to store individual array items one by one. It also means that you'll want to use this approach to pass single-row values, such as the output arguments fetched from a stored procedure.

The PropertyBag object exposes only two methods and one property:

  • The WriteProperty method stores an element into the PropertyBag. The WriteProperty method has three arguments: the first is the name of the property that you want to store; the second is the data value to be stored; and the third is the default value for the property, which is optional. This method will store your data value and the associated name you supply, unless your data value matches the default value. If you specified a data value that matches the default value, no value is stored, but when you use ReadProperty to find this entry in the PropertyBag, the default value passed on to ReadProperty is returned. If you don't specify a default value in your call to WriteProperty, the data value is always stored. Watch out, though—calling WriteProperty twice will write another copy of the data, it won't overwrite the previous value. Also, once a value is in a PropertyBag, there is no way to remove it.
  • The ReadProperty method retrieves an element from the PropertyBag by name. If Visual Basic can't find it, the default value is returned. If there is more than one value with that name, it will return the next in sequence.
  • The Contents property determines the internal state of the PropertyBag. This is exposed as a Byte array that "serializes" the current contents of the PropertyBag. What the documentation does not say out loud is that you can both read from and write to this property, but we'll talk about that later.

Each element of data in the PropertyBag is named so you can reference it later, either reading or writing. Both methods accept an optional argument indicating a default value for the element.

Initially, the PropertyBag object was designed as a mechanism to store any of your control's properties that were set in the VB IDE. That is, if you open a Visual Basic form file in a text editor such as Notepad, you'll see text that you wouldn't normally see on the code window in your application. This text describes the form, the controls, and all of their settings. This is where the PropertyBag stores the property settings of your control, with any binary information being stored in the equivalent FRX file.

When you run the Visual Basic Addin Visual Basic 6.0 ActiveX Control Interface Wizard, it creates PropertyBag code for each property you define in your custom control. If you need more details on how these work, consult MSDN help. The topic "Storing properties using the PropertyBag object" is a good information source.

Similarly, you can make your properties persistent by trapping the Visual Basic WriteProperties event. This event occurs less frequently, usually when the client form is unloaded after a property has been changed within the IDE. Runtime property changes are obviously not stored in this way. Ordinarily, you would not want them to be persistent.

Using the PropertyBag Object to Transport Stuff

Okay, so how can we use a PropertyBag to return data from another tier? Up to this point it seems that all the PropertyBag is good for is to manage Visual Basic form-based controls. Well, consider that the documentation does not really say that you can write to the Contents property. Given that, what if you created a property bag on the server, filled it with a number of named property arguments (even in a hierarchy), and passed the Contents property as a byte array back to the client? Cool? Sure. And fast. However, this approach is not faster than passing back just the variables. On the client end, we simply take the Byte array and apply it to the Contents property of our own locally instantiated PropertyBag object—easy. Of course, those of you using ASP code will not be able to manage byte arrays…

PropertyBag Server Code

Here's the server-side code. It's the same as the previous example except in this case, we pass a Byte array and construct a PropertyBag object to manage the row.

 Public Function GetTitle(ISBNWanted As String) As Byte() Dim pbRetTitle As PropertyBag Set pbRetTitle = New PropertyBag Set cmd = New Command OpenConnection With cmd     .Name = "TitleByISBN"     .CommandText = "TitleByISBN"     .CommandType = adCmdStoredProc     .Parameters.Append _         .CreateParameter("ReturnStatus", adInteger, adParamReturnValue)     .Parameters.Append _         .CreateParameter("ISBNWanted", adVarChar, adParamInput, _20, ISBNWanted)     .Parameters.Append _         .CreateParameter("Publisher", adVarChar, adParamOutput, 20)     .Parameters.Append _         .CreateParameter("City", adVarChar, adParamOutput, 50)     .Parameters.Append _         .CreateParameter("Year_Published", adSmallInt, adParamOutput)     .Parameters.Append _         .CreateParameter("Title", adVarChar, adParamOutput, 255)     .Parameters.Append _         .CreateParameter("Cover", adVarChar, adParamOutput, 255)     Set .ActiveConnection = cn     cmd.Execute End With 

As I said, pretty much the same as the other approaches. Now comes the magic. The following code simply writes each Recordset Field value to named PropertyBag elements. When it comes time to pass back the PropertyBag, we simply pass the Contents Byte array back.

 With pbRetTitle     .WriteProperty "ISBN", ISBNWanted     .WriteProperty "Publisher", "" & cmd.Parameters(enuParms.Publisher)     .WriteProperty "City", "" & cmd.Parameters(enuParms.City)     .WriteProperty "Year_Published", "" & cmd.Parameters(enuParms.Year_Published)     .WriteProperty "Title", "" & cmd.Parameters(enuParms.Title)     .WriteProperty "Cover", "" & cmd.Parameters(enuParms.Cover) End With cn.Close GetTitle = pbRetTitle.Contents End Function 

PropertyBag Client Code

Here's the client code that accepts the data row back from the server. There's nothing complicated about sending Byte arrays over the wire, unlike some of the more sophisticated interfaces we have seen. However, it's more complicated, less maintainable, and harder to code. Moreover, you lose the ability to use this approach from script clients. In a sense, a PropertyBag is conceptually similar to passing XML strings around—both are extensible property repositories that allow for rich or dumb structure but pass on the burden of the extra handling to you. The only difference is the format of the persistence buffer.

 Private Sub cmdQuery_Click() Dim pbLocalTitle As New PropertyBag Dim objLocalAuthors() As objAuthor Dim strGrid As String Set pbLocalTitle = New PropertyBag pbLocalTitle.Contents = GetTitle(ISBNList.Text) Image1.Picture = LoadPicture(pbLocalTitle.ReadProperty("Cover")) With pbLocalTitle strGrid = .ReadProperty("Publisher") & vbTab & _             .ReadProperty("City") & vbTab & _             .ReadProperty("ISBN") & vbTab & _             .ReadProperty("Year_Published") & vbTab & _             .ReadProperty("Title") & vbTab & _             .ReadProperty("Cover") End With With MSHFlexGrid1     .RowSel = 1     .ColSel = .Cols − 1     .Clip = strGrid     .ColSel = 0 End With 

Once the Byte array arrives from the server, applying it to a new PropertyBag object permits you to access each of the properties by name. It couldn't be much easier.


Team-Fly


ADO Examples and Best Practices
Ado Examples and Best Practices
ISBN: 189311516X
EAN: 2147483647
Year: 2000
Pages: 106

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net