{"id":57,"date":"2011-07-22T12:18:23","date_gmt":"2011-07-22T17:18:23","guid":{"rendered":"http:\/\/kratzindustries.com\/CodeRedBlog\/?p=57"},"modified":"2014-03-27T04:36:51","modified_gmt":"2014-03-27T04:36:51","slug":"formclass-mapping-with-custom-provider-control","status":"publish","type":"post","link":"https:\/\/burnt-traces.com\/?p=57","title":{"rendered":"Form\/Class Mapping With Custom Provider Control"},"content":{"rendered":"<p>In my <a href=\"http:\/\/burnt-traces.com\/?p=29\">last article<\/a>, I talked a little bit about taking time to program for yourself. The example used was a drop-down list control that automatically filled itself from an enumeration. Today, we will be looking at the process of filling a form from, and copying data back to, a class. A typical situation for software that deals with user input. Whether its data collection, sales order entry, or whatever, the standard <a href=\"http:\/\/en.wikipedia.org\/wiki\/Create,_read,_update_and_delete\">CRUD <\/a>(create,read,update,delete) theme is repeated over and over again. With anything that is repeated over and over, it can, and probably should be automated. The following is a simplified example of how to replace the process of manually &#8216;gluing&#8217; your forms controls to the underlying class object.<\/p>\n<p>I&#8217;ve explored the process of doing this before in other projects. The original scheme was to create a base class that all other controls\/forms would inherit from that contained all the generic code for filling the controls and updating the class. Although this worked quite well, you can always learn something from exploring a new approach. So, instead of using a universal base control\/form, we will instead be using a <a href=\"http:\/\/msdn.microsoft.com\/en-us\/magazine\/cc164063.aspx\">Custom Provider Control<\/a>. To explain, this is similar to how the ToolTip component works. It provides a service to the form\/control its placed on, and adds a property to each control in the property designer. So our control will provide the service of filling the form with class data, and updating the class data when the user changes what&#8217;s on the form.<\/p>\n<p>First things first, we need to create or provider control. If you read the linked article above, you see that we just have to create a new class that inherits from <code><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.componentmodel.component.aspx\">System.ComponentModel.Component<\/a><\/code>, and implements the <code><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.componentmodel.iextenderprovider.aspx\">System.ComponentModel.IExtenderProvider<\/a><\/code> interface. It also needs to have a <Code><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.componentmodel.providepropertyattribute.aspx\">System.ComponentModel.ProvideProperty<\/a><\/code> attribute, which give the property to be added to controls in the property wizard and also give a control type filter.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n&lt;System.ComponentModel.ProvideProperty(&quot;PropertyName&quot;, GetType(Control))&gt;\r\nPublic Class ControlMapper\r\n    Inherits System.ComponentModel.Component\r\n    Implements System.ComponentModel.IExtenderProvider\r\n<\/pre>\n<p>The property name we give to the <code>ProvideProperty<\/code> attribute is &#8220;PropertyName&#8221;, since what we are mapping our controls to are public properties of a class. The type filter we give it is just <code>Control<\/code>, since we could bind a property to almost any type of control we can code for. That leads us to the implementation of the <code>IExtenderProvider<\/code> interface, which contains only one method, <code><a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.componentmodel.iextenderprovider.canextend.aspx\">CanExtend<\/a><\/code>. <Code>CanExtend<\/code> is called for any control in the form and we return <code>True<\/code> if our class will extend it, or <code>False<\/code> if it will not.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    Public Function CanExtend(ByVal extendee As Object) As Boolean Implements System.ComponentModel.IExtenderProvider.CanExtend\r\n        If extendee.GetType Is GetType(TextBox) Then\r\n            Return True\r\n        Else\r\n            Return False\r\n        End If\r\n    End Function\r\n<\/pre>\n<p>For simplicity of the example, we will only deal with text boxes. I&#8217;ll leave it as an exercise for you to extend the class to handle other controls like combo boxes, picture boxes, calendars, etc. Now, the next thing that needs to be created is a Get and Set function for the property name we gave to the <code>ProvideProperty<\/code> attribute, in the format of <b>Get<\/b><i>PropertyName<\/i> and <b>Set<\/b><i>PropertyName<\/i>. These functions will use a private member <code>Mapped<\/code> which is an instance of <code>Dictionary(of Control, String)<\/code>. This local will track the controls that are being associated to the provider and the property name that was set in the designer. We also set up and event handler when the property is set, so that we can update the forms class when the text is changed by the user.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n\r\n    Public Function GetPropertyName(ByVal myControl As Control) As String\r\n        'Get property name based on control, return empty string if not found\r\n        If Mapped.ContainsKey(myControl) Then\r\n            Return Mapped.Item(myControl)\r\n        Else\r\n            Return &quot;&quot;\r\n        End If\r\n    End Function\r\n\r\n    Public Sub SetPropertyName(ByVal myControl As Control, ByVal value As String)\r\n        'Add property\/control pair to dictionary\r\n        If Mapped.ContainsKey(myControl) Then\r\n            Mapped.Item(myControl) = value\r\n        Else\r\n            Mapped.Add(myControl, value)\r\n        End If\r\n        'Add event handler for control type\r\n        If myControl.GetType() Is GetType(TextBox) Then\r\n            Dim tb As TextBox = myControl\r\n            AddHandler tb.TextChanged, AddressOf Me.TextChanged\r\n        End If\r\n    End Sub\r\n<\/pre>\n<p>Now, we need to add a public property to the provider itself, so the form using it can give it a pointer to the class object that the form is editing. <\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\nPublic Property FormObject As Object\r\n<\/pre>\n<p>And we will add a private field, to mark when we are filling the form. This will server to let us ignore events while we populate controls with class object data. <\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\nDim Filling As Boolean = False\r\n<\/pre>\n<p>Now, the first thing we have to do before we edit data, is that we must load it to be edited. So a method is needed to fill all the associated controls with the value of the property they were mapped to. We first loop through the <code>KeyValuePair(of Control, String)<\/code> that are stored in our <code>Mapped<\/code> dictionary, this gives us the control object and the name of the property it is bound to. <\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\nDim Cntl As Control = item.Key\r\nDim PropertyName As String = item.Value\r\n<\/pre>\n<p>Then, using reflection, we can retrieve the <code>PropertyInfo<\/code> for the property name and use it to get the value from the class object.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\nDim Prop = FormObject.GetType().GetProperty(PropertyName)\r\nValue = Prop.GetValue(FormObject, Nothing)\r\n<\/pre>\n<p>Here&#8217;s the complete fill method, complete with null checks, etc.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    Public Sub FillFromClass()\r\n        'Check for null\r\n        If FormObject IsNot Nothing Then\r\n            Try\r\n                'Set filing flag, use try...finally structure to \r\n                'ensure the flag is always turned off\r\n                Filling = True\r\n                'Loop through all handled controls\r\n                For Each item In Mapped\r\n                    'Get control on property name from dictionary item\r\n                    Dim Cntl As Control = item.Key\r\n                    Dim PropertyName As String = item.Value\r\n                    'Get value from class \r\n                    Dim Value As Object\r\n                    'Get reflection property\r\n                    Dim Prop = FormObject.GetType().GetProperty(PropertyName)\r\n                    'Check null \r\n                    If Prop IsNot Nothing Then\r\n                        'get property value\r\n                        Value = Prop.GetValue(FormObject, Nothing)\r\n                        'Set value according to control type \r\n                        If Cntl.GetType() Is GetType(TextBox) Then\r\n                            'Set text property for text boxes\r\n                            Dim TB As TextBox = Cntl\r\n                            TB.Text = Value\r\n                            'Done!\r\n                        End If\r\n                    End If\r\n                Next\r\n            Finally\r\n                Filling = False\r\n            End Try\r\n        End If\r\n    End Sub\r\n<\/pre>\n<p>As you may have seen in the <code>SetPropertyName<\/code> method, we are adding an event handler to the <code>TextChanged<\/code> event of the text box. This event will handle updating the <code>FormObject<\/code> with the value from the modified control. We can use the <code>GetPropertyName<\/code> function to get the name of the property the control is bound to so that we can update <code>FormObject<\/code> using reflection. <\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    Private Sub TextChanged(ByVal sender As Control, ByVal e As EventArgs)\r\n        'Check for DesingMode\r\n        If Not DesignMode Then\r\n            'Check if the control is being filled\r\n            If Not Filling Then\r\n                'Check for null\r\n                If FormObject IsNot Nothing Then\r\n                    'Get the name of the property bound to control\r\n                    Dim PropetyName = GetPropertyName(sender)\r\n                    'Check if found\r\n                    If PropetyName &lt;&gt; &quot;&quot; Then\r\n                        'Get property using reflection\r\n                        Dim Prop = FormObject.GetType().GetProperty(PropetyName)\r\n                        'Check null\r\n                        If Prop IsNot Nothing Then\r\n                            'Get value based on control type \r\n                            Dim Value As Object\r\n                            If sender.GetType() Is GetType(TextBox) Then\r\n                                'Get text property\r\n                                Value = CType(sender, TextBox).Text\r\n                            Else\r\n                                'Unsupported control type\r\n                                Return\r\n                            End If\r\n                            'Set the value of the class to the new value\r\n                            Prop.SetValue(FormObject, Value, Nothing)\r\n                            'All done!\r\n                        End If\r\n                    End If\r\n                End If\r\n            End If\r\n        End If\r\n    End Sub\r\n<\/pre>\n<p>That completes our provider. Here&#8217;s the complete code.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n\r\n&lt;System.ComponentModel.ProvideProperty(&quot;PropertyName&quot;, GetType(Control))&gt;\r\nPublic Class ControlMapper\r\n    Inherits System.ComponentModel.Component\r\n    Implements System.ComponentModel.IExtenderProvider\r\n\r\n    ''' &lt;summary&gt;\r\n    ''' Dictionary to hold control\/property mapping\r\n    ''' &lt;\/summary&gt;\r\n    ''' &lt;remarks&gt;&lt;\/remarks&gt;\r\n    Dim Mapped As Dictionary(Of Control, String)\r\n\r\n    Public Sub New()\r\n        'Instantiate the dictionary\r\n        Mapped = New Dictionary(Of Control, String)\r\n    End Sub\r\n\r\n    ''' &lt;summary&gt;\r\n    ''' Get function used by the ProvideProperty attribute\r\n    ''' &lt;\/summary&gt;\r\n    ''' &lt;param name=&quot;myControl&quot;&gt;&lt;\/param&gt;\r\n    ''' &lt;returns&gt;&lt;\/returns&gt;\r\n    ''' &lt;remarks&gt;&lt;\/remarks&gt;\r\n    Public Function GetPropertyName(ByVal myControl As Control) As String\r\n        'Get property name based on control, return empty string if not found\r\n        If Mapped.ContainsKey(myControl) Then\r\n            Return Mapped.Item(myControl)\r\n        Else\r\n            Return &quot;&quot;\r\n        End If\r\n    End Function\r\n\r\n    ''' &lt;summary&gt;\r\n    ''' Set function used by the ProvideProperty attribute\r\n    ''' &lt;\/summary&gt;\r\n    ''' &lt;param name=&quot;myControl&quot;&gt;&lt;\/param&gt;\r\n    ''' &lt;param name=&quot;value&quot;&gt;&lt;\/param&gt;\r\n    ''' &lt;remarks&gt;&lt;\/remarks&gt;\r\n    Public Sub SetPropertyName(ByVal myControl As Control, ByVal value As String)\r\n        'Add property\/control pair to dictionary\r\n        If Mapped.ContainsKey(myControl) Then\r\n            Mapped.Item(myControl) = value\r\n        Else\r\n            Mapped.Add(myControl, value)\r\n        End If\r\n        'Add event handler for control type\r\n        If myControl.GetType() Is GetType(TextBox) Then\r\n            Dim tb As TextBox = myControl\r\n            AddHandler tb.TextChanged, AddressOf Me.TextChanged\r\n        End If\r\n    End Sub\r\n\r\n    ''' &lt;summary&gt;\r\n    ''' The IExtenderProvider interface, returns true if the passed control type can be extended.\r\n    ''' &lt;\/summary&gt;\r\n    ''' &lt;param name=&quot;extendee&quot;&gt;&lt;\/param&gt;\r\n    ''' &lt;returns&gt;&lt;\/returns&gt;\r\n    ''' &lt;remarks&gt;&lt;\/remarks&gt;\r\n    Public Function CanExtend(ByVal extendee As Object) As Boolean Implements System.ComponentModel.IExtenderProvider.CanExtend\r\n        If extendee.GetType Is GetType(TextBox) Then\r\n            Return True\r\n        Else\r\n            Return False\r\n        End If\r\n    End Function\r\n\r\n    ''' &lt;summary&gt;\r\n    ''' Used to set the class the form will be updating\r\n    ''' &lt;\/summary&gt;\r\n    ''' &lt;value&gt;&lt;\/value&gt;\r\n    ''' &lt;returns&gt;&lt;\/returns&gt;\r\n    ''' &lt;remarks&gt;&lt;\/remarks&gt;\r\n    Public Property FormObject As Object\r\n\r\n    ''' &lt;summary&gt;\r\n    ''' Internal flag the the form is being filled\r\n    ''' value changes should be ignored when true\r\n    ''' &lt;\/summary&gt;\r\n    ''' &lt;remarks&gt;&lt;\/remarks&gt;\r\n    Dim Filling As Boolean = False\r\n\r\n    ''' &lt;summary&gt;\r\n    ''' Called to initiallize all controls from the values stored in the class\r\n    ''' &lt;\/summary&gt;\r\n    ''' &lt;remarks&gt;&lt;\/remarks&gt;\r\n    Public Sub FillFromClass()\r\n        'Check for null\r\n        If FormObject IsNot Nothing Then\r\n            Try\r\n                'Set filing flag, use try...finally structure to \r\n                'ensure the flag is always turned off\r\n                Filling = True\r\n                'Loop through all handled controls\r\n                For Each item In Mapped\r\n                    'Get control on property name from dictionary item\r\n                    Dim Cntl As Control = item.Key\r\n                    Dim PropertyName As String = item.Value\r\n                    'Get value from class \r\n                    Dim Value As Object\r\n                    'Get reflection property\r\n                    Dim Prop = FormObject.GetType().GetProperty(PropertyName)\r\n                    'Check null \r\n                    If Prop IsNot Nothing Then\r\n                        'get property value\r\n                        Value = Prop.GetValue(FormObject, Nothing)\r\n                        'Set value according to control type \r\n                        If Cntl.GetType() Is GetType(TextBox) Then\r\n                            'Set text property for text boxes\r\n                            Dim TB As TextBox = Cntl\r\n                            TB.Text = Value\r\n                            'Done!\r\n                        End If\r\n                    End If\r\n                Next\r\n            Finally\r\n                Filling = False\r\n            End Try\r\n        End If\r\n    End Sub\r\n\r\n    Private Sub TextChanged(ByVal sender As Control, ByVal e As EventArgs)\r\n        'Check for DesingMode\r\n        If Not DesignMode Then\r\n            'Check if the control is being filled\r\n            If Not Filling Then\r\n                'Check for null\r\n                If FormObject IsNot Nothing Then\r\n                    'Get the name of the property bound to control\r\n                    Dim PropetyName = GetPropertyName(sender)\r\n                    'Check if found\r\n                    If PropetyName &lt;&gt; &quot;&quot; Then\r\n                        'Get property using reflection\r\n                        Dim Prop = FormObject.GetType().GetProperty(PropetyName)\r\n                        'Check null\r\n                        If Prop IsNot Nothing Then\r\n                            'Get value based on control type \r\n                            Dim Value As Object\r\n                            If sender.GetType() Is GetType(TextBox) Then\r\n                                'Get text property\r\n                                Value = CType(sender, TextBox).Text\r\n                            Else\r\n                                'Unsupported control type\r\n                                Return\r\n                            End If\r\n                            'Set the value of the class to the new value\r\n                            Prop.SetValue(FormObject, Value, Nothing)\r\n                            'All done!\r\n                        End If\r\n                    End If\r\n                End If\r\n            End If\r\n        End If\r\n    End Sub\r\n\r\nEnd Class\r\n<\/pre>\n<p>Now, if you build you project, you should be able to drag and drop the provider control right onto your form. <\/p>\n<p><a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlMangerInToolbar.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlMangerInToolbar.png\" alt=\"\" title=\"ControlMangerInToolbar\" width=\"252\" height=\"185\" class=\"alignnone size-full wp-image-72\" \/><\/a><\/p>\n<p>Let&#8217;s create a simple class to test our new control.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\nPublic Class ExampleClass\r\n\r\n    Public Property Name As String\r\n\r\n    Public Property City As String\r\n\r\n    Public Property State As String\r\n\r\n    Public Sub New()\r\n        Name = &quot;Testing Testerton&quot;\r\n        City = &quot;Anytown&quot;\r\n        State = &quot;WI&quot;\r\n    End Sub\r\n\r\nEnd Class\r\n<\/pre>\n<p>Simple enough. We also need a form with some text boxes, like this.<\/p>\n<p><a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlManagerTestForm.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlManagerTestForm.png\" alt=\"\" title=\"ControlManagerTestForm\" width=\"482\" height=\"217\" class=\"alignnone size-full wp-image-73\" srcset=\"https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlManagerTestForm.png 482w, https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlManagerTestForm-300x135.png 300w\" sizes=\"auto, (max-width: 482px) 100vw, 482px\" \/><\/a><\/p>\n<p>After you drag a ControlMapper onto your form, you will notice that it appear in the designer in the component tray. You will also see that each text box will gain a new property.<\/p>\n<p><a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlMapperInTray.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlMapperInTray.png\" alt=\"\" title=\"ControlMapperInTray\" width=\"180\" height=\"82\" class=\"alignnone size-full wp-image-74\" \/><\/a><\/p>\n<p><a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlMapperPropertyOnTextBox.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlMapperPropertyOnTextBox.png\" alt=\"\" title=\"ControlMapperPropertyOnTextBox\" width=\"384\" height=\"129\" class=\"alignnone size-full wp-image-75\" srcset=\"https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlMapperPropertyOnTextBox.png 384w, https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlMapperPropertyOnTextBox-300x100.png 300w\" sizes=\"auto, (max-width: 384px) 100vw, 384px\" \/><\/a><\/p>\n<p>Now for each of the text boxes, you just have to fill in the new PropertyName property with the name of the property in <code>ExampleClass<\/code> you want it to be mapped to. In the example form, we will create a new instance of <code>ExampleClass<\/code> and assign the <code>ControlMapper1.FormObject<\/code> that instance.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n        FormObject = New ExampleClass\r\n        ControlMapper1.FormObject = FormObject\r\n<\/pre>\n<p>Then to demonstrate that the form filling works, we will call <code>ControlMapper1.FillFromClass()<\/code> in the <code>Load<\/code> event of the form.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load\r\n        'Fill the form with the class values\r\n        ControlMapper1.FillFromClass()\r\n    End Sub\r\n<\/pre>\n<p>Lastly, we can demonstrate that the updating works by displaying a message box with the updated values when we click on the button.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click\r\n        Dim Msg As String = String.Format(&quot;Name: {0}, City: {1}, State: {2}&quot;, FormObject.Name, FormObject.City, FormObject.State)\r\n        MsgBox(Msg)\r\n    End Sub\r\n<\/pre>\n<p>Here&#8217;s the complete example form code.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\nPublic Class Form1\r\n\r\n    Dim FormObject As ExampleClass\r\n\r\n    Public Sub New()\r\n        ' This call is required by the designer.\r\n        InitializeComponent()\r\n        ' Add any initialization after the InitializeComponent() call.\r\n\r\n        'Setup form object, and add to control mapper\r\n        FormObject = New ExampleClass\r\n        ControlMapper1.FormObject = FormObject\r\n    End Sub\r\n\r\n    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click\r\n        Dim Msg As String = String.Format(&quot;Name: {0}, City: {1}, State: {2}&quot;, FormObject.Name, FormObject.City, FormObject.State)\r\n        MsgBox(Msg)\r\n    End Sub\r\n\r\n    Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load\r\n        'Fill the form with the class values\r\n        ControlMapper1.FillFromClass()\r\n    End Sub\r\nEnd Class\r\n<\/pre>\n<p>Lets see this in action. First the form fill.<br \/>\n<a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMExampleFormFilled.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMExampleFormFilled.png\" alt=\"\" title=\"CMExampleFormFilled\" width=\"443\" height=\"157\" class=\"alignnone size-full wp-image-78\" srcset=\"https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMExampleFormFilled.png 443w, https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMExampleFormFilled-300x106.png 300w\" sizes=\"auto, (max-width: 443px) 100vw, 443px\" \/><\/a><\/p>\n<p>The let&#8217;s edit the values.<\/p>\n<p><a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMEditedValues.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMEditedValues.png\" alt=\"\" title=\"CMEditedValues\" width=\"441\" height=\"154\" class=\"alignnone size-full wp-image-77\" srcset=\"https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMEditedValues.png 441w, https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMEditedValues-300x104.png 300w\" sizes=\"auto, (max-width: 441px) 100vw, 441px\" \/><\/a><\/p>\n<p>Let&#8217;s click the button to see if the class was updated.<\/p>\n<p><a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMUpdatedMessage.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMUpdatedMessage.png\" alt=\"\" title=\"CMUpdatedMessage\" width=\"478\" height=\"242\" class=\"alignnone size-full wp-image-79\" srcset=\"https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMUpdatedMessage.png 478w, https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/CMUpdatedMessage-300x151.png 300w\" sizes=\"auto, (max-width: 478px) 100vw, 478px\" \/><\/a><\/p>\n<p>It may seem a bit much for a filling a couple text boxes, but when multiple control types are supported, the forms get big, and there are lots of forms, such an automation of the fill-form\/update-object cycle can be a big time saver when building your forms. It reduces coding needed to make the form and update the form, and by implementing a reusable component, reduces the risk of introducing errors when you update.<\/p>\n<p><a href='http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/ControlMapper.zip'>Download the Sample Project.<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In my last article, I talked a little bit about taking time to program for yourself. The example used was a drop-down list control that automatically filled itself from an enumeration. Today, we will be looking at the process of filling a form from, and copying data back to, a class. A typical situation for&hellip;&nbsp;<a href=\"https:\/\/burnt-traces.com\/?p=57\" class=\"\" rel=\"bookmark\">Read More &raquo;<span class=\"screen-reader-text\">Form\/Class Mapping With Custom Provider Control<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"neve_meta_sidebar":"","neve_meta_container":"","neve_meta_enable_content_width":"","neve_meta_content_width":0,"neve_meta_title_alignment":"","neve_meta_author_avatar":"","neve_post_elements_order":"","neve_meta_disable_header":"","neve_meta_disable_footer":"","neve_meta_disable_title":"","footnotes":""},"categories":[5],"tags":[12,13,88,27],"class_list":["post-57","post","type-post","status-publish","format-standard","hentry","category-vb-net","tag-controls","tag-crud","tag-vb-net","tag-winforms"],"_links":{"self":[{"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/posts\/57","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=57"}],"version-history":[{"count":1,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/posts\/57\/revisions"}],"predecessor-version":[{"id":330,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/posts\/57\/revisions\/330"}],"wp:attachment":[{"href":"https:\/\/burnt-traces.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=57"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=57"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=57"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}