Solved

Dynamically access private variable value created and populated in windows form

Posted on 2009-06-29
12
168 Views
Last Modified: 2012-05-07
I use the following code to get the values of textboxes below, but I have 6 private variables that I need to dynamically access in the same way.

I've been looking through System.Windows.Forms.* but cannot find anything that resembles how I would do it.

Please help.
Private Function GetLocalControl(ByVal ctrlName As String) As System.Windows.Forms.Control

        For Each ctrl As Control In Me.Controls

            If ctrl.Name = ctrlName.Trim Then

                Return ctrl

            End If

        Next

        For Each ctrl As Control In gb1.Controls

            If ctrl.Name = ctrlName.Trim Then

                Return ctrl

            End If

        Next

        For Each ctrl As Control In gb3.Controls

            If ctrl.Name = ctrlName.Trim Then

                Return ctrl

            End If

        Next

        Return Nothing

    End Function
 
 

>>From Calling Sub

        xField = CType(GetLocalControl(dvSortFields(j)("field_code_name").ToString), TextBox).Text

        vals(j) = xField

>> perform find using vals

Open in new window

0
Comment
Question by:TSFLLC
  • 6
  • 6
12 Comments
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
(1) What version VB.Net are you working with?

(2) Show us the declaration for your private variables.

(3) Can you show us the relationshiop between the controls and the variables you want to access?  That is to say...for instance, given the name of the control, can you can easily determine the name of the variable you want?
0
 

Author Comment

by:TSFLLC
Comment Utility
Thanks Idle_Mind

1)  The version is VB.NET 2005 Professional
2) The coding snippets are below
3) I populate the variables below.  The glSortOrderFieldName1 = the sort order field name in the table.  I use the glSortOrderFieldTypeX variables to define the field type of  the sort fields are:
d = "Date"
t = "Text"
n = "Long"

I allow for the possibility of six sort fields.  If the glSortOrderFieldTypeX = "" I exit with EndWhile
Then perform a find on the existing or new row in dvGlobalContacts.

dvGlobalContacts in form is sorted based on using the dvTableSortOrder(0)("sort_order_fields").tostring
dvGlobalContacts.Sort = dvTableSortOrder(0)("sort_order_fields").tostring

In saving a row I perform a find on the table after the dvTable is re-freshed with values of the form fields in the order of the user-defined sort order.

Below is the real problem.  I don't know how to code something that would go in place of the ???? in the code snippet below:
???? CType(GetLocalControl("glSortOrderFieldType" & Trim(Str(j))).ToString), variable).Text


Hope all makes sense.

>> As form is initializing

    Private dvTableSortOrder As New DataView

    Private glSortOrderFieldCount As Integer = 0

    Private glSortOrderFieldName1 As String = ""

    Private glSortOrderFieldName2 As String = ""

    Private glSortOrderFieldName3 As String = ""

    Private glSortOrderFieldName4 As String = ""

    Private glSortOrderFieldName5 As String = ""

    Private glSortOrderFieldName6 As String = ""

    Private glSortOrderFieldType1 As String = ""

    Private glSortOrderFieldType2 As String = ""

    Private glSortOrderFieldType3 As String = ""

    Private glSortOrderFieldType4 As String = ""

    Private glSortOrderFieldType5 As String = ""

    Private glSortOrderFieldType6 As String = ""
 

>> Sub that populates the variables

    Private Sub GetUserTableSortOrderValues()

        Dim da As New SqlDataAdapter

        Dim ds As New DataSet

        Dim dt As New DataTable
 

        da.SelectCommand = New SqlCommand

        da.SelectCommand.Connection = TSFConnection

        da.SelectCommand.CommandType = CommandType.StoredProcedure

        da.SelectCommand.CommandText = "SPGS_SelectUserSortOrderDefaults"

        da.SelectCommand.Parameters.Add(New SqlParameter("@TableName", "contact"))

        da.SelectCommand.Parameters.Add(New SqlParameter("@UserID", glUserID))

        da.Fill(ds, "user_account")

        dt = ds.Tables(0)

        dvTableSortOrder.Table = dt

        If dvTableSortOrder.Count > 0 Then

            glSortOrderFieldCount = dvTableSortOrder(0)("field_count").ToString

            glSortOrderFieldName1 = dvTableSortOrder(0)("form_field_name1").ToString

            glSortOrderFieldName2 = dvTableSortOrder(0)("form_field_name2").ToString

            glSortOrderFieldName3 = dvTableSortOrder(0)("form_field_name3").ToString

            glSortOrderFieldName4 = dvTableSortOrder(0)("form_field_name4").ToString

            glSortOrderFieldName5 = dvTableSortOrder(0)("form_field_name5").ToString

            glSortOrderFieldName6 = dvTableSortOrder(0)("form_field_name6").ToString

            glSortOrderFieldType1 = dvTableSortOrder(0)("form_field_type1").ToString

            glSortOrderFieldType2 = dvTableSortOrder(0)("form_field_type2").ToString

            glSortOrderFieldType3 = dvTableSortOrder(0)("form_field_type3").ToString

            glSortOrderFieldType4 = dvTableSortOrder(0)("form_field_type4").ToString

            glSortOrderFieldType5 = dvTableSortOrder(0)("form_field_type5").ToString

            glSortOrderFieldType6 = dvTableSortOrder(0)("form_field_type6").ToString

        End If

    End Sub
 
 

>> From my SaveRecord Sub

>> The ???? represents what I would code to be able to access the value of the glSortOrderFieldNameX variables
 

        GetUserTableSortOrderValues() ' I refresh the user's sort order in certain cases

        Dim j As Int64 = 1, vals(Convert.ToInt16(dvTableSortOrder(0)("field_count").ToString)) As Object, xField As String = "", xField2 As Long = 0, xEndWhile As Boolean = True

        While xEndWhile

            If ???? = "" Then

                Exit While

            ElseIf ????  = "d" Then  '  Field Type = Date

                xField = Format(CDate(CType(GetLocalControl(dvTableSortOrder(0)("form_field_name" & Trim(Str(j))).ToString), TextBox).Text), "MM/d/yyyy hh:mm:ss tt")

                vals(j) = xField

            ElseIf ????  = "t" Then  '  Field Type = Text

                xField = CType(GetLocalControl(dvTableSortOrder(0)("form_field_name" & Trim(Str(j))).ToString), TextBox).Text

                vals(j) = xField

            ElseIf ????  = "n" Then  '  Field Type = Numeric

                xField2 = CLng(CType(GetLocalControl(dvTableSortOrder(0)("form_field_name" & Trim(Str(j))).ToString), TextBox).Text)

                vals(j) = xField2

            End If

            j = j + 1

        End While
 

        j = dvGlobalContacts.Find(vals)

        If j >= 0 Then

            glCurrentContactEntryRow = j

        Else

            glCurrentContactEntryRow = 0

        End If

Open in new window

0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
Let's start with a tip...

Replace your GetLocalControl() function with:

    Private Function GetLocalControl(ByVal ctrlName As String) As Control
        Dim matches() As Control = Me.Controls.Find(ctrlName.Trim, True)
        If matches.Length > 0 Then
            Return matches(0)
        End If
        Return Nothing
    End Function

With regard to the variables...not sure I follow yet.

You have glSortOrderFieldName1 thru glSortOrderFieldName6...and I think you want to do something like?

*** PSEUDO CODE ***

        For i As Integer = 1 To 6
            Select Case glSortOrderFieldName & i
                Case "d"

                Case "t"

                Case "n"

                Case ""
                    Exit Sub

            End Select
        Next

If that is the case then REFLECTION is what you're looking for.  Let me know if the above is what you want and I'll post relevant code.
0
 

Author Comment

by:TSFLLC
Comment Utility
Why are you wanting me to replace my GetLocalControl() function??  Is yours more efficient?

YES, that is exactly what I want to do.  I need to loop through them dynamically and get each value!!

Please post.  I'm curious to see how you're going to use reflection to do this.  Thanks!
0
 

Author Comment

by:TSFLLC
Comment Utility
As far as 'more efficient' evidently you don't have to specify separate panels in order to access the controls.  It allows for accessibility to ALL controls on the form?
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
Correct.  The Controls.Find() method (with the True parameter) will recursively search ALL containers on the form for matches.  GetLocalControl() would then not have to be "fixed" if you were to add more containers or change the name of your existing ones.

There is nothing wrong with hard-coding the search as you did...just thought you would be interested to see a more generic approach.  =)

I'll whip up a simplified Reflection example to demonstrate my above pseudo code...
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 
LVL 85

Accepted Solution

by:
Mike Tomlinson earned 500 total points
Comment Utility
Play with this simple example...hopefully you'll be able to see how to apply it to your situation:    =)
Imports System.Reflection

Public Class Form1
 

    Private glSortOrderFieldName1 As String = "a"

    Private glSortOrderFieldName2 As String = "b"

    Private glSortOrderFieldName3 As String = "c"

    Private glSortOrderFieldName4 As String = "d"

    Private glSortOrderFieldName5 As String = "e"

    Private glSortOrderFieldName6 As String = "f"
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim varBaseName As String = "glSortOrderFieldName"

        Dim varName, value As String

        Dim T As Type = Me.GetType

        Dim fi As FieldInfo

        For i As Integer = 1 To 7 ' <---- I've gone beyond 6 to show what happesn when the field is NOT found (see below)

            varName = varBaseName & i

            fi = T.GetField(varName, BindingFlags.Instance Or BindingFlags.Public Or BindingFlags.NonPublic)

            If Not IsNothing(fi) Then

                value = fi.GetValue(Me)

                MessageBox.Show(varName & " = " & value, "Isn't Reflectoin Cool?", MessageBoxButtons.OK, MessageBoxIcon.Information)
 

                ' this is just to show how you could CHANGE the value as well:

                fi.SetValue(Me, value & " (touched)")

            Else

                MessageBox.Show(varName, "Field Not Found", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)

            End If

        Next

    End Sub
 

End Class

Open in new window

0
 

Author Comment

by:TSFLLC
Comment Utility
This is too good to be true  :) :) :) :)

Including the SetValue.

I know this is asking alot, but I have an open EE question that basically involves the same thing only from a class library ---> private/global variables in a different project form.  Can you either post an example of the changes above or into the other EE posting where you would do the same in a form from class library (CLibrary1) to a form in a project (MyProject) where variable exists.

http://www.experts-exchange.com/Programming/Languages/.NET/Visual_Basic.NET/Q_24512892.html

JackofPH has given a valiant effort, but I'm with 'a paper bag over my head' when it comes to Reflection and this issue and it appears that the code you've included is, with a few minor adjustments, going to resolve that problem also.  I have so much on my mind right now I didn't even realize the two would involve the same ideas.

I will definitely up the ante on your 'beer fund'.  You've helped me MANY times Mike.
0
 

Author Closing Comment

by:TSFLLC
Comment Utility

Very timely in answering and well designed....well documented
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
Glad that was what you needed.  =)

I took a peek at your other question there.  Based on your pseudo snippet:

    Dim frm As String = "MyForm"
    Dim frmID as String = "MyVariable"
    Application.OpenForms(frm).?  

Jack's last link involving Activator is what you're looking for.

Now I haven't dealt with this across projects, though, so I can't give you concrete bullet proof code...but this is how you would do it within the same project:

        Dim frmName As String = "Form2"
        Dim assm As Assembly = Assembly.GetExecutingAssembly
        Dim frm As Form = assm.CreateInstance(assm.GetName.Name & "." & frmName)
        If Not IsNothing(frm) Then
            frm.Show()
        End If

I would ~assume~ that you could do this with any assembly (you use LoadAssembly() probably?)...but here I am showing my inexperience with this topic.  =)
0
 

Author Comment

by:TSFLLC
Comment Utility
Quite alright.  Just tested the other code.  Had to make one minor tweek but works great.

The value I needed was from glSortOrderFieldType + x....not glSortOrderFieldName + x.  Probably an overlook.
0
 
LVL 85

Expert Comment

by:Mike Tomlinson
Comment Utility
Just FYI, there is an alternative to Reflection using the legacy CallByName() method from VB6.  It has a limitation on it, however, in that it only works on PUBLIC fields.  Many find this syntax easier to stomach...it's just not as powerful as Reflection:
http://msdn.microsoft.com/en-us/library/chsc1tx6(VS.80).aspx

Similar example to original using CallByName():
Public Class Form1
 

    ' They have to be PUBLIC for CallByName() to work:

    Public glSortOrderFieldName1 As String = "a"

    Public glSortOrderFieldName2 As String = "b"

    Public glSortOrderFieldName3 As String = "c"

    Public glSortOrderFieldName4 As String = "d"

    Public glSortOrderFieldName5 As String = "e"

    Public glSortOrderFieldName6 As String = "f"
 

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim varBaseName As String = "glSortOrderFieldName"

        Dim varName, value As String

        For i As Integer = 1 To 6

            varName = varBaseName & i

            value = CallByName(Me, varName, CallType.Get)
 

            MessageBox.Show(varName & " = " & value, "Isn't Reflectoin Cool?", MessageBoxButtons.OK, MessageBoxIcon.Information)
 

            CallByName(Me, varName, CallType.Let, value & " (touched)")

        Next

    End Sub
 

End Class

Open in new window

0

Featured Post

Better Security Awareness With Threat Intelligence

See how one of the leading financial services organizations uses Recorded Future as part of a holistic threat intelligence program to promote security awareness and proactively and efficiently identify threats.

Join & Write a Comment

Suggested Solutions

Title # Comments Views Activity
Response back from stored procedure 6 47
Converting C# Objects into JSON file 7 34
Expando 4 31
Change data in datatable 8 13
Article by: jpaulino
XML Literals are a great way to handle XML files and the community doesn’t use it as much as it should.  An XML Literal is like a String (http://msdn.microsoft.com/en-us/library/system.string.aspx) Literal, only instead of starting and ending with w…
I think the Typed DataTable and Typed DataSet are very good options when working with data, but I don't like auto-generated code. First, I create an Abstract Class for my DataTables Common Code.  This class Inherits from DataTable. Also, it can …
Sending a Secure fax is easy with eFax Corporate (http://www.enterprise.efax.com). First, Just open a new email message.  In the To field, type your recipient's fax number @efaxsend.com. You can even send a secure international fax — just include t…
Access reports are powerful and flexible. Learn how to create a query and then a grouped report using the wizard. Modify the report design after the wizard is done to make it look better. There will be another video to explain how to put the final p…

728 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

10 Experts available now in Live!

Get 1:1 Help Now