Macro substitution


Author
Message
Keith Chisarik
Keith Chisarik
StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)
Group: StrataFrame Users
Posts: 939, Visits: 40K
As a VFP developer, the one thing I have missed the most of my old friend "&".

Trying to build controls and/or objects dynamically then loop through them has proven a real PITA, the closest I have come so far is using .NET's control arrays (not even as easy to use as VB6's, but I digress) which have the limitiation of having to be loaded.

So.... being former VFP developers did you put in anything like this?

for x = 1 to n 

l_controlstring = "thisform.txtTextbox" + alltrim(str(n)) + ".backcolor = rgb(255,213,202)"

&l_controlstring

next x

If you did, I'm sold.

Keith Chisarik

Trent Taylor
Trent Taylor
StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)
Group: StrataFrame Developers
Posts: 6.6K, Visits: 6.9K
This is actually quite easy when you know where to look.  When I first wanted to do this it was extremely frustrating because I just wanted to create a macro like in VFP and execute it.  The good news is that this can be done, in a lot of different ways.  It all comes down to reflection and strong-typing.  Since VFP is a weak-typed language this was just a matter of combining some text and hoping that you didn't get an error.  In .NET, it is equally as easy, but you just have to conform to strong-typing.  Let's take your example and turn it into .NET using SF...keep in mind that ThisForm in VFP is not nearly as important in .NET which is referenced by Me.

Option 1
'-- Establish Locals
Dim loControl As System.Windows.Forms.Control

For Each loControl In Me.Controls

    '-- See if the object is a textbox
    If loControl.GetType() Is GetType(TextBox)
        loControl.BackColor = Color.FromArgb(255,213,202)
    End If

Next

Option 2 - Accessing the Property Directly
Controls("txtTextBox1").GetType().GetProperty("BackColor") = Color.FromArgb(255,213,202)

You can also call methods and create objects dynamically using an activator which is similar to macros in VFP.

Sample Class Creation
'-- Establish Locals
DIm lcCmd As String = "MyClass"
Dim loObj As Object

'-- Create the class
loObj = Activator.CreateInstance(lcCmd)

The topic you are asking about will be covered to some degree in our class.  This is also something we could go on about for a good long while.  There are MANY differents to accomplish this, it just depends on what you are attempting to do.

If this doesn't answer your question please let me know.

Keith Chisarik
Keith Chisarik
StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)
Group: StrataFrame Users
Posts: 939, Visits: 40K
** why dont tabs work in my posts? and why is bouble spacing forced? makes for sloppy code examples **

perhaps a practical example is best:

here is some code I wrote that may explain my need, this is my workaround so far.....

For Each ctr In Me.Controls

If TypeOf ctr Is CheckBox Then

curCheckbox = ctr

If curCheckbox.Checked = True Then

If curCheckbox.Name.Length = 9 Then

checkid = curCheckbox.Name.Substring(curCheckbox.Name.Length - 1, 1)

Else

checkid = curCheckbox.Name.Substring(curCheckbox.Name.Length - 2, 2)

End If

If checkid <= 30 Then

texttopass = textarray(Val(checkid) - 1)

labeltopass = labelarray(Val(checkid) - 1)

progresstopass = bararray(Val(checkid) - 1)

pingit(texttopass.Text, progresstopass, labeltopass, curCheckbox, checkid)

End If

End If

End If

Next

 

********************************************************************************

I have those arrays of controls textarray, labelarray, and bararrray preloaded with controls that I might want to change the values of in the PINGIT method (I still call them methods, it is really a function/sub). I pass the entire control based on the array index because I dont know how to programatically create a control reference.

If VFP I could just pass the index, then build a control reference variable and execute a macro substitution. I cant (or dont know how).

Lets take your options 2 since I think it was the closest.

Option 2 - Accessing the Property Directly
Controls("txtTextBox1").GetType().GetProperty("BackColor") = Color.FromArgb(255,213,202)

How would I do that without hardcoding the "1" in "Textbox1"? What is the name of the control to be changed was for instance pulled from a table?

Do you see what I am getting at?

Thanks for looking.... this isnt just me. The other developers in my office (all still semi-novices as .NET) cant get an elegant equivilant to the flexibility of the VFP macro.

I guess the bottom line is how do I dynamically make a reference to a control using variables?

This is wrong but is pseuocode for what I want to do

Dim ctrl as Control

ctrl = "me." + <<variable containing textbox name or part of it (index) >>

ctrl.text = "some text"



Keith Chisarik
Trent Taylor
Trent Taylor
StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)
Group: StrataFrame Developers
Posts: 6.6K, Visits: 6.9K
Here is a sample that shows how to start using reflection.  This is a very basic sample, but should start giving you an idea of how to use reflection.  Honestly, though it may be hard to believe at first, .NET has a much system of communicating with indirect objects.  Once you begin to understand the structure of .NET, the VFP macro will seem clumsy and cumbersome....and practically useless Smile  But believe me, I did not think this at first and I have come a long way since I first wanted to resort back to a weak typed macro.

The first method you need to learn about it GetType().  This method will be instrisically on every object, regardless of the class or control, in .NET.  This is the gateway into reflecting an object or class to get to its properties, methods, events, and so on.

Also, as a side note, you will want to use CType() and GetType() instead of TypeOf.  It will be much faster.  For example, in your code snippet:

If TypeOf ctr Is CheckBox Then

would be faster and more efficient as:

If ctr.GetType() Is GetType(CheckBox) Then

As for the forum questions, press Ctrl+Enter to break for a single line.  Enter takes you to a new paragraph.  As for tab....sorryErmm, you have to use spaces...at least for now.  As for code examples, you can copy from .NET and paste it directly into the editor. It will keep the tabs, but you may have to delete the blank lines and add a Ctrl+Enter to get a single line back in.

Last thing, instead of passing an array over to your pingit method, you should create a generic list with a reference to your controls.

Single Object Type As a CheckBox

'-- Establish Locals
Dim
loCheckBoxesOnly As New System.Collections.Generic.List(Of CheckBox)

loCheckBoxesOnly.Add(Me.CheckBox1)

Any Type Of Control

'-- Establish Locals
Dim loAnyControl As New System.Collections.Generic.List(Of System.Windows.Forms.Control)

loAnyControl.Add(Me.CheckBox1)
loAnyControl.Add(Me.Textbox1)
loAnyControl.Add(Me.Textbox2)

I hope this helps.  Please let me know if things are still a little fuzzy. My explanation may not be the best.


Attachments
VFPMacroSample.zip (136 views, 684.00 KB)
Keith Chisarik
Keith Chisarik
StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)
Group: StrataFrame Users
Posts: 939, Visits: 40K
Great stuff there and I may be dense since it is getting late, but....

You code all has a hardcoded reference like "Textbox1"

How do you make your code flexible so that it can accept any/many controls (ie. TEXTBOX(x) ) with passing an explicit reference to a control:

Here is VFP code I cannot reproduce:

IF ALLTRIM(this.Value) <> ALLTRIM(g_emailaddress)
 For x = 1 To 4 && 4 contacts
  l_fieldname = "thisform.pgfCorpInfo.page5.chkCont"+Alltrim(Str(x))+"_primary.value"
  If &l_fieldname = .T.
    l_emailfield = "thisform.pgfCorpInfo.page5.txtCont"+ALLTRIM(STR(x))+"_email.value"
    &l_emailfield = ALLTRIM(this.value)
  Endif
 Next x
ENDIF

See how l_fieldname references 4 controls here since I am BUILDING the name? THAT is what I dont get.

Replection DOES look awesome though.

I must not be explaining myself well, but I do promise to buy ya a beer August 11th for putting up with it Smile

Keith Chisarik

Trent Taylor
Trent Taylor
StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)
Group: StrataFrame Developers
Posts: 6.6K, Visits: 6.9K
That is what I am trying to illustrate.  TextBox1 is not a direct reference, you could just as easily put in a local variable here.  If I wanted to directly reference the TextBox1, there would not have been quotes and I would have made a call like this:

TextBox1.GetType()

Does that make sense?  Regardless of VFP or .NET, you have to have some base reference.  For example, a form, user control, containter, etc. that you know will exist in order for you to enumerate the controls within it.  Or create controls.  In your example, your base would be "thisform.pgfCorpInfo.page5" which you would then iterate through the Controls collection of this container object and begin using reflection to determine what to do, if anything, with that object.

DIm loControl As Control
Dim loType As System.Type

For Each loControl In Me.pgfCorpInfo.Page5

   '-- Save off the type of the control
   loType = loControl.GetType()

   '-- See if this control need to be updated
   If loType.IsSubClassOf(TextBox) Then
       CType(loControl, TextBox).Text = "MyValue"
   ElseIf loType.IsSubClassOf(CheckBox) Then
       CType(loControl, CheckBox).Checked = True
   End If


Next

So in this example you really are not using as much reflection as just making sure that the objects are properly typed.  For whatever it is worth, you can do what you are trying to do.  You can do practically ANYTHING in .NET.  The thing is that you have to properly reflect the objects in order to set them or execute methods.  You can test on object names, values, literllay anything.  But just as you already knew where you were planning to look in your VFP code, you have to have a point of reference to at least start from before you can reflect to the objects dynamically.

Keith Chisarik
Keith Chisarik
StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)
Group: StrataFrame Users
Posts: 939, Visits: 40K
Cool Ill try this all out....... thank you.

Keith Chisarik
Keith Chisarik
Keith Chisarik
StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)StrataFrame VIP (1.6K reputation)
Group: StrataFrame Users
Posts: 939, Visits: 40K
I found this out on the net somewhere and the light went on:

       For i As Integer = 1 To 3
            CType(Me.Controls("Label" & i), Label).Text = "Text Number " & i
        Next

I get it............. BigGrin

Keith Chisarik

Trent Taylor
Trent Taylor
StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)StrataFrame Developer (10K reputation)
Group: StrataFrame Developers
Posts: 6.6K, Visits: 6.9K
Good deal.
Ross L. Rooker, Sr.
Ross L. Rooker, Sr.
StrataFrame User (197 reputation)StrataFrame User (197 reputation)StrataFrame User (197 reputation)StrataFrame User (197 reputation)StrataFrame User (197 reputation)StrataFrame User (197 reputation)StrataFrame User (197 reputation)StrataFrame User (197 reputation)StrataFrame User (197 reputation)
Group: Forum Members
Posts: 153, Visits: 462
Basically I needed to dynamically load an assembly, then call a user control from that assemby. The assembly was not know at design time so it could not be set as a reference at design time. The user control can vary and typically is in a string from a table. IE... not known at design time. Then I needed to pass 3 parameters to the user control dynamically using reflection. Since the user control is not know at design time, I needed to use reflection. The code below shows what I learned from this. Works like a charm. 

 

                       //textboxWhere.Text = lcSelect;

                        // Here is how to create an instance of a Form class just from knowingits name in a string.

                        // You can use the System.Reflection.Assembly.CreateInstance method tocreate a form from its name. Below is a code snippet.

                        // The name in the textbox has to be the full name including itsnamespace. So if there is a class named Form2 in namespace MyCompanyName,

                        // thenthe textbox would contain MyCompanyName.Form2. This snippet also assumes thatthe class is defined in the current executing assembly.

                        // If not, you would have to create an instance of the assembly thatcontains the class instead of calling the static method GetExecutingAssembly.

                        // As noted on this board, using reflection in this manner might affectperformance.

                            UserControl uct;

                            //Assembly tempAssembly = Assembly.GetExecutingAssembly();

                            // if class is located in another DLL or EXE, use somethinglike

                            // Assembly tempAssembly =Assembly.LoadFrom("myDLL.DLL");

                            Assembly tempAssembly = Assembly.LoadFrom(@"C:\CMTAskAtRuntimeUserControls\CMTAskAtRuntimeUserControls\bin\Release\CMTAskAtRuntimeUserControls.dll");

                            // or

                            // Assembly tempAssembly =Assembly.LoadFrom("myEXE.exe");

                            //Form frm1 = (Form)tempAssembly.CreateInstance(textBox1.Text);// as Form;

                            //frm1.Show();

                           uct = (UserControl)tempAssembly.CreateInstance(strAskAtRunTimeUserControl);

                            Type t = uct.GetType();

                            object[] p = { lcSelect };

                            t.GetMethod("SetParams").Invoke(uct, p);

                            object[] q = { strReportfilename };

                            t.GetMethod("SetParamsRptFile").Invoke(uct, q);

                            object[] r = { strNodetext };

                            t.GetMethod("SetParamsReportName").Invoke(uct, r);

                           panelManagerAskAtRunTime.Controls.Clear();

                            //// what default viewer do you want to use ie... grid orreport.... need to enhance this to show the GRid Viewer

                           Logiware.CMT.Forms.EasyQuery.frmReportViewer frmRpt = newLogiware.CMT.Forms.EasyQuery.frmReportViewer();

                           panelManagerAskAtRunTime.Controls.Add(uct);

                            uct.Dock = DockStyle.Fill;

                           panelManagerAskAtRunTime.Visible = true;



 

The code behind the control in this example. This user control is in a totally different class project and is not referenced in the main solution above other than in code. Notice the:
  • using System;

    using System.Collections.Generic;

    using System.ComponentModel;

    using System.Drawing;

    using System.Data;

    using System.Text;

    using System.Windows.Forms;

     

    namespace CMTAskAtRuntimeUserControls

    {

        public partial class uctSalesReport: MicroFour.StrataFrame.UI.Windows.Forms.UserControl

        {

            // just always at least include these although currentlyonly the SQLselect is being passed this may change.

      

            public stringlcSelect { get; set;}

            public string rptFile{ get; set; }

            public stringreportName { get; set;}

     

            // here is the spot to set the BO and Binding Source up

           Logiware.CMT_DLL.boCompany bc = new Logiware.CMT_DLL.boCompany();

           MicroFour.StrataFrame.Business.BusinessBindingSourcebs = new MicroFour.StrataFrame.Business.BusinessBindingSource();

           

     

            public uctSalesReport()

            {

               InitializeComponent();

     

               bs.BusinessObject = bc;

               bc.FillDataTable("SELECT * FROMtbl_Company_1");

                this.dataGridView1.DataSource = bs;

            }

     

     

            public voidSetParams(string slsl)

            {

                        lcSelect = slsl;
  •             this.textbox1.Text = lcSelect;

            }

     

            public voidSetParamsRptFile(string prmRptFile)

            {

               rptFile = prmRptFile;

            }

     

     

            public voidSetParamsReportName(string prmReportName)

            {

               reportName = prmReportName;

            }

     

     

            private voidtoolStripButtonContinue_Click(object sender, EventArgs e)

            {

               Logiware.CMT.Forms.EasyQuery.frmReportViewerfrmRpt = new Logiware.CMT.Forms.EasyQuery.frmReportViewer();

     

                //// this will take care of everything to display thereport in the default viewer

                Logiware.CMT.ClassLibrary.clsReportViewer.showReport(lcSelect, frmRpt,rptFile, reportName, lcSelect);

            }

        }

    }

     


GO

Merge Selected

Merge into selected topic...



Merge into merge target...



Merge into a specific topic ID...




Similar Topics

Reading This Topic

Login

Explore
Messages
Mentions
Search