I'm not sure it's best-practices but over time I've found my programming style is changing to be a lot more abstract...working at a level where I don't care what the property names are when displaying/retrieving data from the user.
Normally I don't just give out my thoughts on the problems that I'm helping with because I've learned that my approach to solving problems is vastly different than the people asking about the problem. I find it's easier to get insight into how the user thinks to give them a solution that they can easily understand and is their style of programming.
Here is a snippet of what I was talking about earlier...the code is clean, and simple and easy to use/maintain.
I have a Web User Control that has a Label to display a prompt/text and a TextBox that is used to display and gather data. This control is called "FieldUserControl" for simplicity and has 2 important properties: the Text property (which gets and sets the TextBox.Text property) and the Prompt property (which gets and sets the Label.Text property). It has other properties for styling etc but we won't get into them because I want to keep my point clear.
Now say we have a page (or user control) and we want to let the user see/edit a bunch of Text Properties of a class "XYZ".
First of all I would declare a ListOf FieldUserControls (at Page level scope), used as a container for all the FieldUserControls required to let the user see/edit the XYZ's properties.
Then in the Page Init Event I would use Reflection (so you need to import the namespace) to rip through the all the Properties in XYZ, create a FieldUserControl for each one, give the FieldUserControl the ID that matches the property name, and add the FieldUserControl to the page and to the ListOf FieldUserControls:
-
Imports System.Reflection
-
'......
-
Private _xyzFields As List(Of FieldUserControl) 'a container for all the FieldUserControls required to display/retrieve data for XYZ
-
Private urlToFieldControl As String = "~/FieldUserControl.ascx" 'Path to the FieldUserControl
-
-
Private Sub MyPage_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
-
_xyzFields= New List(Of FieldUserControl)
-
InstantiateXyzFields()
-
End Sub
-
-
Private Sub InstantiateXyzFields()
-
'Grabbing all of the properties for class XYZ
-
Dim xyzFieldProperties() As PropertyInfo = GetType(XYZ).GetProperties
-
-
'Ripping through each XYZ property
-
For i As Integer = 0 To xyzFieldProperties.Length - 1
-
'Creating a FieldUserControl control to represent the property
-
Dim f As FieldUserControl= CType(Page.LoadControl(_urlToFieldControl), FieldUserControl)
-
-
'Getting the property information
-
Dim pi As PropertyInfo = xyzFieldProperties(i)
-
-
'Setting the ID of the FieldUserControl to the property name
-
f.ID = pi.name
-
-
'Setting the Prompt for the FieldUserControl to the property name
-
f.Prompt = pi.name
-
-
'Adding the FieldUserControl control to a Panel that is on the page where we want
-
'the FieldUserControls to be displayed
-
PanelThatContainsXYZsFields.Controls.Add(f)
-
-
'Adding the field control to the list of fields for later use
-
_xyzFields.Add(f)
-
Next
-
End Sub
Now we have a FieldUserControl control (a Label-TextBox pair) for every property that is part of the XYZ class added to the page....prompt is set with the name of the property so that the user can identify what it is (what's really nice is that you can set up resources that contain prompts in the languages that your application supports...using the property names as the Key value for each prompt...that way you can retrieve the translated text/user friendly prompt for each property easily)
At this time we have FieldUserControls added to the page with prompts but the TextBoxes don't contain any information. Say XYZ has a method called "Populate" that goes to the database, retrieves the information, and populates the class's properties with the data retrieved.
I would call this method in the Page Load event only if isPostback=false (the first time the page is loaded). Then I would loop through all of the properties for the class and set the corresponding FieldUserControl's Text property:
-
-
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
-
If IsPostBack = False Then
-
DisplayXYZData()
-
End If
-
End Sub
-
-
Private Sub DisplayXYZData()
-
'Creating an instance of the XYZ class
-
Dim instanceOfXYZ As New XYZ
-
-
'Populating the instance of the class with data
-
instanceOfXYZ.Populate()
-
-
'Grabbing all of the properties for class XYZ
-
Dim xyzFieldProperties() As PropertyInfo = GetType(XYZ).GetProperties
-
-
'Ripping through each XYZ property
-
For i As Integer = 0 To xyzFieldProperties.Length - 1
-
'Getting the property information
-
Dim pi As PropertyInfo = xyzFieldProperties(i)
-
-
'Getting the property name & storing it into a string (for Lambda expression to work nicely)
-
Dim propertyName As String = pi.Name
-
-
'Using the Array.Find method to retrieve the FieldUserControl that corresponds with the property
-
'Note that I'm using a Lambda expression for simplicity sake
-
Dim f As FieldUserControl = Array.Find(_xyzFields.ToArray, Function(x) String.Compare(x.ID,propertyName)=0)
-
-
'Making sure that the Array.Find method worked...that f exists before trying to use it
-
If f IsNot Nothing Then
-
'Setting the FieldUserControl's Text property with the value of the property
-
'that is in the instanceOfXYZ object
-
f.Text = pi.GetValue(instanceOfXYZ,Nothing)
-
End If
-
Next
-
End Sub
-
Tada: done.
We are displaying all properties of a class (whether it be 1 or 1000) on the screen with a Label for each property and a TextBox for each property. The TextBoxes are displaying data for the properties....what more could you ask for?
Oh retrieveing data is just as simple: get all the properties for the class, get the corresponding FieldUserControl for the property...use the property Info's SetValue method to set the class with the data in the TextBox.
-
Private Sub RetrieveXYZData()
-
'Creating an instance of the XYZ class
-
Dim instanceOfXYZ As New XYZ
-
-
'Grabbing all of the properties for class XYZ
-
Dim xyzFieldProperties() As PropertyInfo = GetType(XYZ).GetProperties
-
-
'Ripping through each XYZ property
-
For i As Integer = 0 To xyzFieldProperties.Length - 1
-
'Getting the property information
-
Dim pi As PropertyInfo = xyzFieldProperties(i)
-
-
'Getting the property name & storing it into a string (for Lambda expression to work nicely)
-
Dim propertyName As String = pi.Name
-
-
'Using the Array.Find method to retrieve the FieldUserControl that corresponds with the property
-
'Note that I'm using a Lambda expression for simplicity sake
-
Dim f As FieldUserControl = Array.Find(_xyzFields.ToArray, Function(x) String.Compare(x.ID,propertyName)=0)
-
-
'Making sure that the Array.Find method worked...that f exists before trying to use it
-
If f IsNot Nothing Then
-
'Setting the instanceOfXYZ's property with the value of the Text property
-
'that is in the corresponding FieldUserControl object
-
pi.SetValue(instanceOfXYZ, f.Text, BindingFlags.GetField, Nothing, Nothing, Nothing)
-
End If
-
Next
-
End Sub
-Frinny