Making our Code More Dynamic

In a previous post I showed how we could dynamically create a UI based on some XML, however the properties we wanted to set were known because we wrote the XML. I want to follow up with an extension of that sample that can dynamically set the properties on our objects that we’re creating by reading the property names from the XML as well.


We need to rewrite the Dynamic class so that it can get and set the properties dynamically. We’ll turn to VB’s CallByName function to help us (this is similar to the SetProperty() VFP method). Currently this function only works with simple types, however, so we cannot dynamically set our colors with this technique, though it can still be powerful in many scenarios. Let’s take a look:


My new XML document looks like the following: 


<?xml version=1.0 encoding=utf-8 ?>


<questions>


  <question>


    <assembly>System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</assembly>


    <control>System.Windows.Forms.TextBox</control>


    <text>This is the first survey question.</text>


    <height>35</height>


    <readonly>true</readonly>


    <tabstop>false</tabstop>


    <multiline>true</multiline>


  </question>


  <question>


    <assembly>System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</assembly>


    <control>System.Windows.Forms.TextBox</control>


    <text>This is the second survey question.</text>


    <height>100</height>


    <readonly>true</readonly>


    <tabstop>false</tabstop>


    <multiline>true</multiline>


  </question>


  <question>


    <assembly>System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</assembly>


    <control>System.Windows.Forms.Label</control>


    <text>This is the third survey question.</text>


    <height>80</height>


    <tabstop>false</tabstop>


  </question>


  <question>


    <assembly>System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</assembly>


    <control>System.Windows.Forms.Button</control>


    <text>This is the fourth survey question.</text>


    <height>30</height>


    <tabstop>false</tabstop>


  </question>


</questions>


 


Now we just read the list of properties from the document. We can do this easily in VB 8 using a DataSet again:


‘Read the xml into a dataset for easier processing of the elements


Dim myData As New DataSet()


myData.ReadXmlSchema(CurDir() & “\questions.xsd”)


myData.ReadXml(CurDir() & “\questions.xml”)


Dim survey As DataTable = myData.Tables(0)


 


‘Read the properties from the XML


Dim props As New List(Of String)


For Each dc As DataColumn In survey.Columns


    props.Add(dc.ColumnName)


Next


‘Now add all the questions defined in the questions.xml file


For Each row As DataRow In survey.Rows


    Me.AddQuestion(row, props)


Next


Now we can pass this list of properties into the Dynamic function along with the info object which can either be a DataRow in this case or our static QuestionInfo object we created previously. Note that I didn’t change the QuestionInfo class definition, this code will ignore any properties that are not found on the info object or ones that cannot be set on the return object. This makes the code more dynamic because now we don’t necessarily know the type of the object we’re creating or the properties that are being set on it:


Option Strict Off


 


Public Class Dynamic


 


    ”’ <summary>


    ”’ Dynamically creats an object and sets properties on it


    ”’ by reading properties on the passed in object.


    ”’ </summary>


    ”’ <param name=”info”>An object with the property values</param>


    ”’ <param name=”properties”>The list of properties to set from the info


    ”’ object onto the created object</param>


    ”’ <returns></returns>


    Shared Function GetQuestion(ByVal info As Object, ByVal properties As List(Of String)) As Object


        Dim c As Object


        Dim propValue As Object


        Try


 


            c = System.Reflection.Assembly.Load(info!Assembly).CreateInstance(info!Control)


 


           ‘VB does an automatic conversion at runtime


            For Each prop As String In properties


                Try


                   ‘Late bound call – we don’t know the type or the value 


                    propValue = info(prop)


                Catch ex As Exception


                    propValue = Nothing


                End Try


 


                If propValue IsNot Nothing AndAlso propValue IsNot System.DBNull.Value Then


                    Try


                        CallByName(c, prop, CallType.Set, propValue)


                    Catch ex As Exception


                        ‘if we can’t set a property on the object, just ignore


                    End Try


                End If


            Next


 


        Catch ex As Exception


            ‘Try/Catch is required here, as this code will cause


            ‘ a runtime error if the the type cannot be created.


            c = New TextBox


            c.Text = ex.ToString


            c.MultiLine = True


            c.Height = 100


            c.ReadOnly = True


            c.ScrollBars = ScrollBars.Vertical


        End Try


 


        Return c


    End Function


 


End Class


 


 I’ve attached the new sample to this post. No one can deny that VB still has a long way to go to enable better support here, but we can see that the beginings of dynamic programming in Visual Basic today.


Enjoy!

DynamicUI.zip