There have been a number of requests for a tutorial on how to use the GDI+x classes and the Shiny Glass buttons. I am used to using these classes, so wrongly assumed that all users were up to speed. So I decided to fix that and post a tutorial about how to install and use GDI+x and the button class.
Also I have made some updates to the class. It now respects the Enabled property. Also updated is the builder. Tooltips, colours & fonts remembered, and a live form preview, courtesy of Paco. Download below.
Lets go...
Step 1 - Download and install the GDI+x classes
The classes can be downloaded from the VFPX site from this page:
http://www.codeplex.com/Wiki/View.aspx?ProjectName=VFPX&title=GDIPlusX
Click on the link on this page that says Latest Release of GDIPlusX and download the latest stable release. Do not download the Beta as that is not complete and may not work properly
After downloading, extract the files to a directory.
2. Download the new improved Shiny Glass buttons class from the attachment below. Extract that to another folder. Open the class in VFP and if it asks you where to find the GDIPLUS.VCX, navigate to the \source directory where you extracted the GDI+x classes and you will find gdiplus.vcx there. Now close and save the class to resolve the links. This is because I do not supply the GDI+x classses and I do not know where you could have extracted them.
3. Drop a button instance on a form. In VFP, from the menu Tools open the Class Browser. Then open the bbGlassbuttonsX.vcx in the Class Browser. Highlight the "glassbutton" item and drag and drop it on the form using the icon at the top left as shown.

4. Right click on the button and select "Properties' from the popup.

5. In the properties window, select the "Favourites" tab, highlight the property "aaGlassBtnBuilder" and click on the small button that appears.

6. The builder will now appear with the default settings. You can now change the colours as shown by the arrows.

The image below shows where each colour and font setting goes.

7. Set your font properties

8. Click "Apply" to updte the preview. New. The button on your form will also update with an image of what your button looks like.
9. Click Exit to close the builder. Your properties will have been set to what you want and the form will show the button.

10. You are all set. Run the form and see that you now have a Shiny Glass Button that is responsive to your mouse movements. You can add code to the CLICK event of the button as normal.


As mentioned I have made improvements to the Builder:
Tooltips, Colour and Font selection remembers original set colours and font attributes. A bitmap is generated when you click Apply so you can now see what the button will look like on your form.(Thanks to Paco)
The class has also been updated. It now respects the Enabled property so that you can now set the Enabled property for the button as shown below.

I hope this tutorial shows you how to use these buttons. Enjoy and get a pair of sun glasses if the glare off the shiny buttons gets too much. :)
In a previous post I showed a class to generate "Aqua" buttons using GDI+x from codeplex.
This post is all about some modifications I made to that class to enable me to produce Shiny Glass Buttons. Also I did not explain the techniques in obtaining the effect. This post will fix that and I will try to explain as best I can, the inner workings of the class.
The Glass Button
Basically the class uses a subclassed Imgcanvas control from the GDIPLUS.VCX classes that you need to download from the link above. The classes INIT should not be touched. Instead use the SETUP method to run any code you'd normally run in the INIT.
.Setup
This
.originalht = This.Height
This
.originalwidth = This.Width
* resize to fit the shadow
This
.Width = This.Width + This.shadowOffset
This
.Height = This.Height + This.shadowOffset
The original height and width are saved and the canvas is increased to allow the shadow to display. This must be done in the Setup method.
.BeforeDraw
Here's where the magic happens.
* Declarations
Local
loGfx As xfcGraphics
Local
loBrush1 As xfcBrush
Local
loBrush2 As xfcBrush
Local
loBrush3 As xfcBrush
Local
loBrush4 As xfcBrush
Local
loRect1 As xfcRectangle
Local
loRect2 As xfcRectangle
Local
loRect3 As xfcRectangle
Local
path1 As xfcPath
Local
path2 As xfcPath
Local
path3 As xfcPath
Local
loFont As xfcFont
Local
loStringFormat As xfcStringFormat
loGfx
= This.oGfx
Local
nButtonColour1 As Integer, nButtoncolour2 As Integer, nButtoncolour3 As Integer, nButtoncolour4 As Integer
With _Screen
.System.Drawing
The canvas is now cleared to the parents background colour which means that these buttons can be placed in a container as well.
* clear
loGfx.Clear(.Color.FromRGB(This.Parent.BackColor))
* read in the colours from control's the properties
nButtonColour1 = .Color.FromRGB(This.pnButtoncolour1)
nButtoncolour2 = .Color.FromRGB(This.pnButtoncolour2)
* this is one of the options of the Drawing2D.SmoothingMode
loGfx.SmoothingMode = .Drawing2D.SmoothingMode.AntiAlias
The main button is drawn here. A rectangle to define its position and size is created.
* main button
loRect1 = .Rectangle.New(This.btnOffset,This.btnOffset,This.originalwidth, This.originalht)
The GetPath method, just plots a path with the button's dimensions, but rounds the corners as per the curvature set in the pnbtnCurvature property
path1 = This.GetPath(loRect1, This.pnbtnCurvature) && second param less = less curve
This code flips the colours used based on the MouseEnter and MouseLeave and creates the gardient brush to draw.
IF This.Hover
loBrush1 = .Drawing2D.LinearGradientBrush.New(This.Rectangle, nButtonColour2,nButtoncolour1,90,.T.)
ELSE
loBrush1 = .Drawing2D.LinearGradientBrush.New(This.Rectangle, nButtonColour1,nButtoncolour2,90,.T.)
ENDIF
loBrush1.GammaCorrection = This.Hover

The button Normal and Hover(below) states

* shadow
The same rectangle used above is used here except we offset the Left and Top by the ShadowOffset. This is the reason we resized the object in .SETUP. so that the shadow would be visible. A pathgradient brush is used.
loRect2 = loRect1
loRect2.offset(This.shadowOffset, This.shadowOffset)
path2 = This.GetPath(loRect2, This.pnbtnCurvature)
loBrush2 = .Drawing2D.PathGradientBrush.New(path2)
loBrush2.CenterColor = .Color.Black
loBrush2.SurroundColors = .Color.FromRGB(This.Parent.BackColor) && fade into background
Here's what the shadow looks like when drawn

* lighter top half
loRect3 = .Rectangle.New(This.btnOffset+2,This.btnOffset+2,This.originalwidth -(This.btnOffset+4),;
This.originalht/2 + This.btnOffset)
path3 = This.GetPath(loRect3, This.pnbtnCurvature,.T.)
nButtoncolour4 = .Color.FromRGB(This.pnButtonColour4)
nButtoncolour3 = .Color.FromRGB(This.pnButtonColour3)
IF This.Hover
loBrush3 = .Drawing2D.LinearGradientBrush.New(loRect3,nButtoncolour4,;
nButtoncolour3, .Drawing2D.LinearGradientMode.Vertical)
ELSE
loBrush3 = .Drawing2D.LinearGradientBrush.New(loRect3,nButtoncolour3,;
nButtoncolour4, .Drawing2D.LinearGradientMode.Vertical)
ENDIF
Same as above except the rectangle is changed and the curvature for the bottom 2 curves is doubled for effect.
This is the result of the above code:

Normal State (above) and Hover (below)

The 3 object and then drawn in this sequence.
loGfx.FillPath(loBrush2, path2) && shadow

loGfx.FillPath(loBrush1, path1) && dark main

loGfx.FillPath(loBrush3, path3)

The above 3 lines actually draw the images onto the imgcanvas(ignore the text for now)
Finally the Text is drawn using the standard GDI+x code
* draw the text
nButtonfontcolour = .Color.FromRGB(This.pnButtonFontColour)
loBrush4 = .SolidBrush.New(nButtonfontcolour)
loRect = .Rectangle.New(This.btnOffset, This.btnOffset, This.Width-This.shadowOffset,This.Height-This.shadowOffset)
* Get a basic string format object, then set properties
loStringFormat = .StringFormat.New()
loStringFormat.Alignment = .StringAlignment.Center
loStringFormat.LineAlignment =.StringAlignment.Center
* Create a Font object
loFont = .Font.New(This.pcButtonFontName,This.pnButtonFontSize, .FontStyle.Bold, .GraphicsUnit.Point)
* draw it
loGfx.DrawString(This.pcButtonCaption , ;
loFont, loBrush4, loRect, loStringFormat)
Endwith
This code produces the button below
with the same button in "Hover" state.

I have also atached code to the MouseEnter/MouseLeave, MouseDown/MouseUp to handle these states and give a visual feeedback. The Hover effect, just flips the gradient colours. The MouseDown/MouseUp redefines the rectangle with an offset giving the appearance of the button being pressed and released.
So its just a matter of dropping the class on a form and sizing it to your needs.
I have made most changable properties Favourites so those are the only ones that need to be changed.

To assist, I have also designed and attached a live builder. This builder is just a form class that is called from the MemberData script of the custom property aaGlassBtnBuilder with this script code. This code is very generic, so if ever you need to attach a custom builder you can modify this snippet for calling your own builder. Also check out the code in the builder for how the properties are read and set.

Memberdata Editor with script code.
The clicking on the builder button displays the builder which has a live preview. Make your changes and click "Apply" to update the class properties and update the preview. The preview is exactly how your button will finally look at runtime.

Here are some samples I created with this class.

Also note that just by changing the colours used and the curvature of the corners you can produce a huge variety of spectacular glass buttons. Here are a few more I created just by changing the colour sequence and the curvature.

As usual the full source code for the class and the builder are included in the attached file. Download and create your own Glass buttons courtesy of GDI+x and me. I have not included any sample form in the attachment.
Only the class is included but then that is all you need. That and some imagination on your part. The rest is done by my class and of course the GDI+xclasses.
Note:
As mentioned in other posts,
I dont include the gdiplusc.vcx since you need to download the latest from the VFPx site.
Just open the form/class in VFP and when it asks you for the Imgcanvas, navigate it to the gdiplusx.vcx on your computer. The form/class will then resolve the location correctly. Save the form/class, set the default path to the directory where your form is (to find any images) and then run the forms. I have subclassed the imgcanvas class from the gdiplusx.vcx class library. Unfortunately this would happen since I don't supply the gdiplusx.vcx and I don't know where a user might have stored it.
The VFP Image base class now has the RotateFlip property where the image set as the Picture property can be rotated and/or flipped.
The different states for the VFP control are:
0 - Rotate0FlipNone
1 - Rotate90FlipNone
2 - Rotate180FlipNone
3 - Rotate270FlipNone
4 - RotateNoneFlipX
5 - Rotate90FlipX
6 - Rotate180FlipX
7 - Rotate270FlipX
(Funnily enough these are exactly the same enumerations in the GDI+x classes.
)
However the Image base class has a problem. It cannot show an image background as transparent if the RotateFlip property is anything other than 0. This can esaily be illustrated in this images below, where the Image control has Backstyle = 0 Transparent

When the RotateFlip is changed to non 0 the background is no longer transparent, even at runtime and this is a big failing.

To the rescue comes the GDI+x classes. Since this is an Image control, all image properties are available that you usually set - Picture, BackStyle, Stretch, RotateFlip etc.
With just a few lines of code inserted in the GDI+x ImgCanvas class we can make sure that our BackStyle setting is respected by the image class at runtime even if the RotateFlip property is non 0.
The attached file (link at bottom) contains this class that will do this for you. All you need to do is drop it on a form, set the normal properties you would set, set a custom property as I will show later on and when the form is run, the image will respect your settings.
In the image below the class is dropped on a form along with normal VFP image base classes. All these objects have the RotateFlip set to 2 - Rotate180FlipNone.

As you can see the controls do not respect the Backstyle property which has been set to 0 - Transparent when the RotateFlip has been changed and this persists even at runtime.
To the left above are two instances of my class and to the right, two instances of the VFP base image class. There are two BMP's involved, one with a white background and the other with a Majenta (RGB(255,0,255) background.
The only properties that need setting, I have added to the Favourites tab. I have also added some MemberData code to the TransparentColour property to allow selection from the VFP Colour Selector, since an integer colour is needed here. Click on the Property and then the button that will appear to change the colour.
The TransparentColour property is the colour that you want to make invisible. In the image on the left it is White and in the image on the right it is Majenta.
The default for the class is White as shown below:

The Image on the right has been changed as shown below, using the button provided.

The result, at runtime is that while the VFP Baseclasses do not handle the BackStyle property at all when RotateFlip is non 0, the GDI+x class with the addition of my code does this very well.

I have barely scratched the surface of these classes. There is scope for many, many improvements for enhancing the functionality of the lowly VFP image base class.
But hold on - There's more. There is one added benefit that this class brings and that again has to do with the BackStyle property of the VFP image class. With the VFP base class, if Backstyle was set to 0 - Transparent, then any pixel of the image that was white (RGB(255,255,255) ) was made completely transparent. A number of images from the web use another colour to signify the transparent colour. So images with colour other than white as background, would not work since you are restricted to white only, with the base class.
In the form below, the same image is assigned to the VFP Base image class on the left and my enhanced class on the right. The BackStyle of both are set to 0 - Transparent. As you can see the backcolour for this image we want to be invisible is Magenta - RGB(255,0,255)

Note that I have changed the TransparentColour property of my class to 16711935 which is the Majenta colour.
At runtime my class does it's work and makes any pixel of the image with that colour transparent as you can see below.

Now that's 2 for the price of one by any reckoning.![Big Smile [:D]](/emoticons/emotion-2.gif)
Note:
As mentioned in other posts,
I dont include the gdiplusc.vcx since you need to download the latest from the VFPx site.
Just open the form in VFP and when it asks you for the Imgcanvas navigate it to the gdiplusx.vcx on your computer. The form will then resolve the location correctly. Save the form, set the default path to the directory where the form is (to find the images) and then run the form. I have subclassed the imgcanvas class from the gdiplusx.vcx class library. Unfortunately this would happen since I don't supply the gdiplusx.vcx and I don't know where a user might have stored it.
Any ideas for further improvement are most welcome.
Class uppdated with Builder Preview 30/09/2008
The class in the attached zip, is an example of what you can do to spruce up your application. It contains an AquaButton class which uses the Imgcanvas object from the GDI+x classes on Codeplex.
This class is very easy to use especially since I have added in a Builder. It is just a matter of dropping an instance of the class on a form, setting the properties manually or using the provided builder and Bob's your Uncle.

The class needs just a few properties as shown here. All properties that can be changed are in the "Favourites" tab.
- bCaption - the caption to be displayed on the button
- buttonfont - the font to be used for the button text
- buttoncolour - the ARGB colour to be used for the button. Better to use the builder for this.
- buttonfontcolour - the colour of the button text. See the point above.
- buttonfontsize - size of the button text font.
The item AquabuilderX is the builder used for setting all these properties in one shot.. When you select it, a button appears which if clicked, will display the custom builder, included in the class.

Set the properties of the selected Aquabutton using the builder. Click Apply to apply these changes and update the preview.

And run the form. The GDI+x classe does its magic and produces this clickable button with an Aqua look, for the properties set as above. Notice the shadow as well?

The button has a "Hover" effect and changes colour when the mouse is over it.

As well, it has some animation so that you can get feedback when it is clicked.
Here are some other samples I did earlier. As you can see you can have then any size or shape as long as they are rectangular.
The sample shows the buttons on a form as well as in a container.

Cesar, Bo and Craig have done a fantastic job in translating the .NET classes into a VFP class that is very easy to use. There are heaps of samples all over the internet and since these classes emulate the .Net classes, any C# or VB code can easily be translated into VFP.
With a little imagination, this class can be used to enhance your GUI as well as provide a number of enhancements to your Class Library arsenal. Over the next few months I will be adding to the series of posts by Cesar, on this class, with a number of posts my own, showing some practical examples of usage. Hopefully it will encourage others to start using these classes and benefit from them.
Also I want to say that I have been looking at these classes for a few weeks only and the support I received from Cesar and Bo, for my various queries, was really out of this world. Thanks guys.
Note:
As mentioned in other posts,
I dont include the gdiplusc.vcx since you need to download the latest from the VFPx site.
Just open the form in VFP and when it asks you for the Imgcanvas navigate it to the gdiplusx.vcx on your computer. The form will then resolve the location correctly. Save the form, set the default path to the directory where the form is (to find the images) and then run the form. I have subclassed the imgcanvas class from the gdiplusx.vcx class library. Unfortunately this would happen since I don't supply the gdiplusx.vcx and I don't know where a user might have stored it.
Enjoy.
Everyone who has used XP would have seen the effect produced when a user opts to shutdown Windows XP. To see it you click the "Start" button and then select ShutDown, which brings up the windows shutdown dialog similar to the one below.
The question is why would anyone click "Start" when they want to "Stop"? But that is another story...

You may have also noticed that windows slowly fades the coloured background down to grey, leaving the coloured dialogbox to appear more prominent. The colour of the desktop is restored if the user cancels this operation.
This same effect is possible in VFP forms and applications by using the GDI+x classes found on codeplex.
The class I created will do this for you for any form you drop it on, and call its methods. This class (download link below) uses the Imgcanvas object so to use it you will need to download the GDI+x classes.
Usage is extremely simple. You just drop it on the main form of a SDI or add it to _screen. When you need to produce the effect, you just call its SHOWLIGHTBOX() method and to remove the effect call the HIDELIGHTBOX() method. As calling sample is shown below which could be added to an Exit or Quit button:
bb = ThisForm.bbGdilightbox1.Showlightbox()
IF MESSAGEBOX("Are you sure you want to Quit?",308,"GDI+X Lightbox",0) = 7
bb = ThisForm.bbGdiLightbox1.Hidelightbox()
RETURN
ELSE
ThisForm.Release
ENDIF
Basically what happens when the ShowLightbox method is called is that using GDI+ an image of the mainform is captured, the lightbox class expands to overlay the whole form and the image is painted on the imgcanvas. A timer is kicked off in the background and the class returns control to the code.
The timer in the background increments a variable and calls the imgCanvas.Draw. The variable affects the way the ColorMatrix is created and this changes the colours of the screen image. With repeated calls the colour is "faded" till the image is grey. The timer then stops.
To restore, the class is just made invisible again.
The code to produce this effect comes from an article by Cesar in the UT mag. without which this class would not have been possible.
A sample form where you can test this as well as a pseudo messagebox form is also included in the download for this article. Just make sure you have the GDI+x classes, run SYSTEM.APP and then run the form:

Sample form with coloured background and VFP controls.
Click the "Exit" button to see the effect as the messagebox appears and the background slowly fades to grey.

Sample form with the form and controls faded to grey.
Complete source code is provided for anyone to modify as they please. Enjoy.
Update: Since I do not include the gdiplusx.vcx (as this must be downloaded from the VFPX site) and since I have subclassed the imgcanvas class found in the gdiplusx.vcx classlibrary, you need to resolve the link to the class yourself.
Just open the form in VFP and when it asks you for the Imgcanvas navigate to the gdiplusx.vcx on your computer where you will find the imgcanvas class. The form will then resolve the location correctly. Save the form, set the default path to the directory where the form is (to find the images) and then run the form.
Unfortunately this would happen since I don't supply the gdiplusx.vcx and I don't know where a user might have stored it. Thanks to Mike S for pointing that out.
In
my earlier post I showed a Lightbox class done in VFP.
Mike S posed a problem:
I've got one issue with it when placed on a VFP form that contains an
ActiveX control (MS webbrowser). The lightbox is not able to capture
the contents of the ActiveX, only the hosting VFP form. Is there anyway
to have it include the ActiveX content as well?That got me thinking because I did not provide for Activex and as we all know, they always insist on being the topmost item on a VFP form. The only way to hide them is to set them as invisible.
But that would leave the screen looking like crap.
The idea that came to me was to "pull the wool over the user's eyes" so as to say. Hide the Activex but make it appear that it is still visible.
If you're a VFP developer and are looking for GDI+x there is no other place better than
Cesar's blog. So the rescue comes GDI+x and after browsing Cesar's site a while I found what I was looking for. Thanks Cesar. You are the best.
So I adapted the class and to use the new version you must have the GDI+x classes from codeplex, as it now uses SYSTEM.APP from the
GDI+X classes. Place this in along with the files from the download link below.
The idea I had is this. As part of the LightBox appearing, I first iterate through the controls of the form looking for any Activex objects. If I find any, I add an image object to the form, then grab a partial screen capture of the Activex, load that into the new image object, hide the Activex and show the new image instead.
With VFP and GDI+x classes this is fast.
Each image object so added is stored in a class array for cleaning up later.
So the call to Lightbox and everything else is the same. I just added a couple of methods and properties to handle Activex.
If the user clicks
NO on the messagebox, then I again iterate through all the Activex objects and make them visible and
RemoveObject all the image objects added earlier. A call to Refresh refreshes the objects.
Here is a form with 2 Activex objects, a MA DateTime Picker and a Web Browser Control.

And here is the same form after the user has clicked the LightBox button
You cannot tell that the Activex are really images now can you?Note: 1. You must have the SYSTEM.APP from the
GDI+X classes. This class will not work without it.
2. Due to calling Refresh, the Web Browser control wants to reload the site again. That cannot be helped since otherwise you will find that the area covered by it will not refresh when Visibility is toggled by the class.
Thanks also Mike S for posing the question and getting me thinking.
Enjoy
Update: 14th Sep 2008Some folks are still having problems which stem from 2 things.
1. They are using VFP9Sp1 so the Pictureval used in the class does not work on PNG's. I have permanently changed the mask to a TIFF,
2. I have also included the TIFF mask file in the zip. Just change the property maskfile to point to the full path + filename of the mask file whereever you store it.
3. They have SET DELETED OFF so cannot see the mask. I have "packed" the class to remove the deleted records and also added code in the init to set/reset the environment to take care of that.
Please let me know if there are any other problems.
The final piece of the puzzle
One of the things I have always wanted to do was to be able to expose the objects contained in the Usercontrol as well as their properties without writing thousands of Set and Get statements. After all if you take a simple control with 4 textboxes, there are literally thousands of properties that would require Sets and Gets to be exposed using the Interop Toolkit template. I always knew there had to be an easier way. Well the other day while re-reading this article(http://www.sweetpotatosoftware.com/SPSBlog/CommentView,guid,3dd24f92-a52c-4bb0-8121-c2e6e2cc4f93.aspx) from Craig Boyd and this line popped out at me:
“Also, I've provided an optiongroup that will set the RenderMode of the toolstrip and menustrip just to show that we aren't limited to events that we have exposed through the interface. Public objects and their properties are accessible as well.”
So I downloaded Craig’s C# sample and looked at the code. Two things I noticed – Craig was defining all the objects as Public and using the AutoDual attribute for the class. So this is what I tried to do and succeeded. This blog entry is about how this can be achieved. Follow along using VB Express.Net or the full blown VStudio.
Start up VB.Net and create a new Interop User control project. Name the project MyVbButtonInterop and save it in a separate directory. I prefer my own directory since I hate the paths MS choose as default.
Open the design file and add a button as below.

Double-Click the button to open the code window and add this simple code there:

Compile your project. Switch to VFP and open a new form. Insert an ActivexControl object and look for your newly created Activex in the list.

Select it to add it to the form. Open the properties window and see that there are very few properties exposed

Run the form and click the button. Nothing happens. This is because we have not wired in any events for exposure.
Quit from VFP. Note because the dll is cached in VFP if you need to change it (and we do) you need to completely close VFP. Do this every time throughout this exercise.
Back to VB and in the code view for the control if you scroll up and expand the VB6 regions you will find the area where you should add your code to wire in your methods. Note that as of writing I have not found proper a way around this. You have to expose your events here so add this code in this section

and in the click code of the button change it to this

Build again and when you open the form in VFP you will find that there is a new event available called ButtonClicked.

Double click the Activex and in the ButtonClick event add some of your own code

Run the form and click the button. A message box appears

and when you click to close it your code fires and you see the wait window

Close VFP and back to VB. We are now going to expose all the properties with just a few steps.
Towards the top of the InteropUserControl.vb you will find this:
<ComClass(MyVbButton.ClassId, MyVbButton.InterfaceId, MyVbButton.EventsId)> _
Public Class MyVbButton
Change it so that it looks like this:

Build the project and try to open the form in VFP. You may get this error

No problem. The registration failed. So we use Regasm with the /codebase option to register it. Regasm is the utility used by Net to register Activex as we used Regsvr32 for other activex. It can be found in your .Net directory so open a command prompt and navigate to it.

Run Regasm on your dll which is found here


and this is the result you will see

The Activex has been registered, but you see this warning message about being unsigned.
Lets sign the assembly. For this you need to create a strongname pair that you can use to sign your assembly. You create it using the file SN.EXE that is in the SDK which you can download from MS. We will do that later.
Back in VFP open your form and it opens without any error. But check out the property sheet of the control. There are heaps more properties here since we changed the Interface to AutoDual. But these properties are only for the container not the button which is what we want.

Back in VB (you did close vfp completely?) and we need to enable the option to show all files. VB hides them from us. So click the cotton in the project pane to show all files, expand the InteropUserControl.vb node and open the file that was hidden so long called InteropUserControl.Designer.vb.

When you add any object to the control, in the background VB generates the code to implement this object. In our case it is the button added and is implemented here, always Friend by default.

Since the AutoDual Interface will expose all public objects, we need to change this declaration to Public if we want to see it in VFP.

Compile the control and open the form in VFP again. You will not need to re register it with regasm.
Now in VFP when you start typing, intellisense comes in and you find a new object called Button1. This is our button we declared as Public. You can now change all its properties from within VFP. You just don’t get intellisense.

So go ahead and change the code to this.

Run the form and click the button. The message box appears, your wait window message next and finally the button is disabled!

Voila we have exposed the Button and all its PEM’s to VFP with just a few changes.
Let’s try this with a property of the container control. Add a button to the form and add code like this to it

Why backColor_2 ? Well I am not sure but I think this is because of overloaded methods used by .Net. Run the form and click the new button

select a colour and see that you also have the properties of the container exposed as well.

But this is only a button and VFP already has buttons. Ah, but what if you dropped a toolstrip control and then replaced all the Friend declarations with Public? Then every object on the toolstrip would be exposed allowing you complete control without all those thousands of Sets and Gets. Now that exercise I leave to you since that was the whole purpose of this post – to show how to expose PEM’s with just a few lines of code.
One final piece is to get the assembly signed with a strong name.
First we need to create the file for signing and we use SN.exe from the .Net sSDK for this. It is found here on my computer. Download and install it.

So open a command prompt there and enter this command:

and then copy the generated file into your project directory
.

Now we need to reference it in our project so back in VB (with vfp closed) open the file AssemblyInfo.vb

And just below the other Assembly attributes, add the line as shown. Make sure the full correct path is entered to your .SNK file

Now rebuild and when you run regasm again you get no errors or warnings. Our assembly has now been signed with a strong name.

Here are a few links I found useful when authoring this post.
http://www.sweetpotatosoftware.com/SPSBlog/CommentView,guid,3dd24f92-a52c-4bb0-8121-c2e6e2cc4f93.aspx
http://www.sweetpotatosoftware.com/SPSBlog/PermaLink,guid,df3f1be8-62bc-491c-935e-570ebfe53164.aspx
* about AutoDual
http://www.programmersheaven.com/2/vbrad-Interop
* adding the strong key in VB
http://visualbasic.about.com/od/usingvbnet/a/FWTools5_2.htm
http://www.15seconds.com/issue/060309.htm
http://support.microsoft.com/kb/313891
Some final notes:
With just a few lines I have shown how you can expose your .NET activex objects without bothering with Set's and Get's. Of course you will also find a huge number of other PEM;s exposed, but just ignore them.
You will unfortunately have to manually expose all your methods as shown. There is an Invoke method exposed but as yet I have not found out how to use it since it expects a parameter of type _delegate.
However now it is a simple matter of creating your controls and exposing key events. All the properties will be exposed if the techniques described her are followed.
I have attached the complete, signed dll along with the source, but it is better to start from scratch and DIY as you will learn better. This code is for reference only.
This is a control that will display your data in a repeated sequence. Unlike a normal grid, this control can show multiple lines from the same record, thus giving you the ability to display data in a scrollable container with no restriction on the number of fields to display. There are a number of examples of a DataRepeater to be found but it is better to visualise it than to describe it, so here is my DataRepeater control in action.

This control is very easy to setup and use as you will see. Just a few steps and a few properties to set. So here goes.
Because of the way classes are implemented in VFP you cannot add an object from a form, only from a class, Therefore there is an additional step required for setting up this class.
Open a new form, resize it and add a datarepeater object to it as shown below


The form above has the DataRepeater control added to it. This is just a container into which you will place your fields. This control is DataBound so all controls dropped into it must also be databound.
The easiest way to add fields, is to open a table in the form DE and drag and drop fields from there into the container. The table can be deleted from the DE after you are done adding fields.
In the image below I have added fields from the CUSTOMER table found in the \SAMPLES\DATA directory of VFP. Notes field was added to show memos in action.

Now re-arrange and resize the fields as well as resize the container as needed. Once you are satisfied with the result, select the container and save it as a class – from the menu File|SaveAs Class and save it into the bbDataRepeater class library. I have saved my class as customerdata.

The class instance along with the fields, can now be deleted from the form once you have saved it as a class..
Next insert a datarepeatergrid object on the form. Since I plan to have 2 panels of repeating data I need to make my form large enough to fit since the grid will expand at runtime to accommodate the 2 panels. This is dependant on the number of fields used since the larger the datarepeater with fields is, the larger will be the grid.

Once that’s done it is now a matter of setting a few properties of the datarepeatergrid object.
The properties that need to be set are shown here as I have made them all favourites.


That is all. Now the form is ready, so run it..
Clicking on the buttons will fire the custom method buttonclicked and you can see that the class knows which record you are on.

Download the class and a sample form from the link below.
Enjoy.
A LightBox dialog technique in VFP
You may or may not have heard of the LightBox Dialog UI Effect. It is one of the current effects making the rounds, and has been described as the "Interaction Design Technique of the Year" on this page where design awards for 2008 were announced -
http://www.useit.com/alertbox/application-design.html (scroll down midway)
Well this effect can very easily be implemented in VFP with a simple image and a PNG with a mask.
You may recall that I showed the usage of PNG's with transparent masks to enhance the GUI in these posts:
http://weblogs.foxite.com/bernardbout/archive/2006/09/11/2436.aspx
http://weblogs.foxite.com/bernardbout/archive/2006/11/04/2798.aspx
and showed a technique for embedding images in these:
http://weblogs.foxite.com/bernardbout/archive/2007/02/18/3320.aspx
http://weblogs.foxite.com/bernardbout/archive/2007/07/15/4366.aspx
At the end of this post will be a class where you can get this LightBox effect in your VFP applications. It uses a masked PNG that is "Embedded" into the class so no external files are needed.
The class is just dropped on a form or into a container on the form and when needed, the Display() method is called passing a couple of parameters. As described elsewhere, the LightBox is useful to focus a user's attention on a modal messagebox. Therefore the Display() method needs to be called just before displaying the modal form and after to remove it.
The sample form provided shows how this can be called using the VFP MessageBox() but you can very easily substitute that for your own modal messagebox form as per your own design. That is beyond the scope of this post, which is just about the LightBox class.
Here the class is added to the Form as well as a container in the Form in the VFP IDE.

This is the code from a method called from the Exit button:
LPARAMETERS tcMsg
LOCAL lRet as Boolean
ThisForm.lightbox1.Display(.F.,.T.)
IF MESSAGEBOX(tcMsg,292,"Are you sure?",0) = 7
lRet = .F.
ELSE
lRet = .T.
ENDIF
ThisForm.lightbox1.Display()
RETURN lRet
The Display() method is called with 2 optional parameters. The First parameter is the Object over which the LightBox will be overlaid, and if .F. , the parent object is assumed. The second is to switch the class on or off.
ThisForm.lightbox1.Display(.F.,.T.)
means Show the LightBox for the form(default)
This shows the form running. The Lightboxes are not visible.

Here the Container Lightbox is toggled on

And finally the LightBox class in action on the form. See how it emphasises the messagebox?

This effect makes the messagebox stand out and being modal, the user is forced to read the message and act on it. As I said earlier, it is not too difficult to use your own custom messagebox. All that is required is to insert a call to the LightBox.Display() just before showing the Messagebox and immediately after, to hide it.
Enjoy.
19/08/2008 Update
Thanks to Cyril & Cesar for finding this. The class had deleted records hence the image mask was not loading. Download has been updated. Also PNG's changed to BMP because of VFP handling of PNG's. Please download latest version below.
19/08/2008 2nd Update
This tip is from Cesar (http://weblogs.foxite.com/vfpimaging)
With this tip you can implement the LightBox class with very few changes as it wraps your original MessageBox() calls.
Where ever you want to use the LightBox class along with a messagebox() - example is for the Exit button:click()
#DEFINE MESSAGEBOX LightBoxMsgBox
IF MESSAGEBOX("Are you sure you want to quit",292,"Are you sure?",0) = 7
RETURN
ELSE
ThisForm.Release
ENDIF
Then, create a small PRG that will wrap the original MESSAGEBOX command Call it LIGHTBOXMSGBOX.PRG
LPARAMETERS tcMessage, tnType, tcTitleBarText, tnTimeOut
LOCAL loForm as Form
loForm = _Screen.ActiveForm
loForm.lightbox1.Display(.F.,.T.)
LOCAL llReturn as Boolean
llReturn = MESSAGEBOX(tcMessage, tnType, tcTitleBarText, tnTimeout)
loForm.lightbox1.Display()
RETURN llReturn
This way, you wont need to change any code in your forms, just add the line below
#DEFINE MESSAGEBOX LightBoxMsgBox
in a header ".H" file, linked to your forms class. Great tip Cesar.
20/08/2008
Updated zip file to v1.03. New property maskfile to use an external maskfile.
This is because only VFP9Sp2 handles PNG's properly when using the PICTUREVAL property. If the property is left empty then it will load the internal PNG - (for Sp2)
Also corrected version of Cesar's sample code.
[snip]
MESSAGEBOX() command returns integer values, not boolean, so the function will stay better this way:
LPARAMETERS tcMessage, tnType, tcTitleBarText, tnTimeOut
* Some few tweaks in the parameters, in order to make MESSAGEBOX()
* work as desired, for the case when some parameters are missing
tnType = EVL(tnType, 0)
IF VARTYPE(tcTitleBarText) <> "C"
tcTitleBarText = "Microsoft Visual FoxPro"
ENDIF
IF NOT VARTYPE(tnTimeOut) $ "NI"
tnTimeOut = 0
ENDIF
* Find the LightBox object and activate it
IF TYPE("_Screen.ActiveForm.Name") <> "C"
* Could not locate an active form
RETURN
ENDIF
LOCAL loForm as Form
loForm = _Screen.ActiveForm