{"id":29,"date":"2011-07-13T22:44:16","date_gmt":"2011-07-14T03:44:16","guid":{"rendered":"http:\/\/kratzindustries.com\/CodeRedBlog\/?p=29"},"modified":"2014-03-27T04:43:45","modified_gmt":"2014-03-27T04:43:45","slug":"create-an-enum-combobox-in-vb-net","status":"publish","type":"post","link":"https:\/\/burnt-traces.com\/?p=29","title":{"rendered":"Create an Enum ComboBox in VB.Net"},"content":{"rendered":"<p>There are many things to consider when you write code. Often times you are focused on what you are trying to deliver to your customer. Lately, I&#8217;ve been trying to focus more on what will make my job as a programmer easier. Mostly that boils down to two things I like in my code, re-usability\u00a0and ease of updating. In the past I&#8217;ve found myself writing the same code over and over again, and when it came time for changes, updating the same code in a bunch of different places.<\/p>\n<p>Consider this, you have a reasonably large number of forms\/controls in your application and many of them contain a drop-down list of the same set of values. Usually, you might just edit each combo box and type in the values for each instance of the list on each form\/control it appears on. However, if you need to update those values, you now have to do it in many places and you may forget one and thus introduce a bug into your program. One solution is to create a drop-down list that automatically loads its values from an enumeration. That way every instance of this list will always be the same and can be added by just dropping it onto the form\/control without having to set its properties.<\/p>\n<p>To do this, you need to first create a new class that inherits from <code>ComboBox<\/code> and accepts a type parameter <code>T<\/code>. This will be your generic base class that will do all the work.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\nPublic Class EnumComboBox(Of T)\r\n    Inherits ComboBox\r\nEnd Class\r\n<\/pre>\n<p>Since you are inheriting from <code>ComboBox<\/code>, your new control has most of the functionality it needs already. Next, it&#8217;s just a matter of using reflection over the enumeration type passed in the type parameter <code>T<\/code> to fill in the <code>DataSource<\/code> property. You can do this in the constructor, and it looks like this:<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    Public Sub New()\r\n        MyBase.New()\r\n        'Drop down list style, no text entry\r\n        Me.DropDownStyle = ComboBoxStyle.DropDownList\r\n        'Get type variable\r\n        Dim EnumType As Type = GetType(T)\r\n        'Check if it really is a enum\r\n        If Not EnumType.IsEnum Then\r\n            Throw New Exception(String.Format(&quot;Type {0} is not an enumeration.&quot;, EnumType.Name))\r\n        End If\r\n        'Get enum values\r\n        Dim Values() As T = &#x5B;Enum].GetValues(EnumType)\r\n        'Setup datasource\r\n        'Use linq query \r\n        Dim NewItems = From x In Values Select Key = &#x5B;Enum].GetName(EnumType, x), Value = x\r\n        'Set datasource to NewItems\r\n        DataSource = NewItems.ToList\r\n        'set display and value members\r\n        DisplayMember = &quot;Key&quot;\r\n        ValueMember = &quot;Value&quot;\r\n    End Sub\r\n<\/pre>\n<p>First we are setting the <code>DropDownStyle<\/code> property to <code>DropDownList<\/code>, as this disables the free-entry text box portion of the ComboBox. The next statement, <code>Dim EnumType As Type = GetType(T)<\/code>, retrieve a type variable that contains the reflection information we need. We also added a check to the <code>IsEnum<\/code> property just to make sure that the type parameter is actually and enumeration type. The line, <code>Dim Values() As T = [Enum].GetValues(EnumType)<\/code>, is pretty simple and just retrieves an array of all the values in the enumeration. Next, we are using a LINQ statement to pair up each value with its name into an <code>IEnumerable<\/code> of a generic type. Note that we gave the properties in the generic type the specific names Key and Value. Then we set the <code>Datasource<\/code> property to be <code>NewItems.ToList<\/code>. Setting the <code>Datasource<\/code> directly to the LINQ query object doesn&#8217;t work, as the <code>ComboBox<\/code> class doesn&#8217;t seem to recognize query objects as a valid data source. <code>ToList<\/code> processes the query and converts it into a list object. Lastly, we just set the <code>DisplayMember<\/code> and <code>ValueMember<\/code> properties to &#8220;Key&#8221; and &#8220;Value&#8221;. <\/p>\n<p>There are two other additions to this control. One is simply a property that exposes <code>SelectedValue<\/code> as type <code>T<\/code> rather that just plain <code>object<\/code>. This mostly just helps when coding against the control.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    Public ReadOnly Property EnumValue As T\r\n        Get\r\n            Return SelectedValue\r\n        End Get\r\n    End Property\r\n<\/pre>\n<p>The other addtion is just a hack to work around some problems with the forms designer. Basically what happens is the designer tries to serialize properties from the controls when you place them on a form\/control. Well, if you try to serialize our <code>datasource<\/code> property, it will fail since it can&#8217;t serialize an anonymous type. That error will prevent you from adding your control to a form\/control.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\n    &lt;System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)&gt;\r\n    Shadows Property DataSource\r\n        Get\r\n            Return MyBase.DataSource\r\n        End Get\r\n        Set(ByVal value)\r\n            MyBase.DataSource = value\r\n        End Set\r\n    End Property\r\n<\/pre>\n<p>That leaves us with the complete control code, shown here.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\nPublic Class EnumComboBox(Of T)\r\n    Inherits ComboBox\r\n\r\n    Public Sub New()\r\n        MyBase.New()\r\n        'Drop down list style, no text entry\r\n        Me.DropDownStyle = ComboBoxStyle.DropDownList\r\n        'Get type variable\r\n        Dim EnumType As Type = GetType(T)\r\n        'Check if it really is a enum\r\n        If Not EnumType.IsEnum Then\r\n            Throw New Exception(String.Format(&quot;Type {0} is not an enumeration.&quot;, EnumType.Name))\r\n        End If\r\n        'Get enum values\r\n        Dim Values() As T = &#x5B;Enum].GetValues(EnumType)\r\n        'Setup datasource\r\n        'Use linq query \r\n        Dim NewItems = From x In Values Select Key = &#x5B;Enum].GetName(EnumType, x), Value = x\r\n        'Set datasource to NewItems\r\n        DataSource = NewItems.ToList\r\n        'set display and value members\r\n        DisplayMember = &quot;Key&quot;\r\n        ValueMember = &quot;Value&quot;\r\n    End Sub\r\n\r\n    &lt;System.ComponentModel.DesignerSerializationVisibility(System.ComponentModel.DesignerSerializationVisibility.Hidden)&gt;\r\n    Shadows Property DataSource\r\n        Get\r\n            Return MyBase.DataSource\r\n        End Get\r\n        Set(ByVal value)\r\n            MyBase.DataSource = value\r\n        End Set\r\n    End Property\r\n\r\n    Public ReadOnly Property EnumValue As T\r\n        Get\r\n            Return SelectedValue\r\n        End Get\r\n    End Property\r\nEnd Class\r\n<\/pre>\n<p>Now, another issue with the Visual Studio form designer, is that you cannot add a generically defined control through the control toolbox. To get it to work in the designer you just have to create a non-generic class, like this.<\/p>\n<pre class=\"brush: vb; title: ; notranslate\" title=\"\">\r\nPublic Class ComboBoxExample\r\n    Inherits EnumComboBox(Of ExampleEnum)\r\n\r\nEnd Class\r\n<\/pre>\n<p>At this point, if you build your project, <code>ComboBoxExample<\/code> should appear in your toolbox to be dropped onto your control.<\/p>\n<p><a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/combobox.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/combobox-300x164.png\" alt=\"\" title=\"New control in ToolBox\" width=\"300\" height=\"164\" class=\"alignnone size-medium wp-image-38\" srcset=\"https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/combobox-300x164.png 300w, https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/combobox.png 561w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>That&#8217;s it. You now have a reusable drop down list, based on an enumeration that, no matter where it&#8217;s used will always reflect the correct values.<\/p>\n<p><a href=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/combobox2.png\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/combobox2-300x174.png\" alt=\"\" title=\"Enum Combo Box in action\" width=\"300\" height=\"174\" class=\"alignnone size-medium wp-image-39\" srcset=\"https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/combobox2-300x174.png 300w, https:\/\/burnt-traces.com\/wp-content\/uploads\/2011\/07\/combobox2.png 547w\" sizes=\"auto, (max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>There are many things to consider when you write code. Often times you are focused on what you are trying to deliver to your customer. Lately, I&#8217;ve been trying to focus more on what will make my job as a programmer easier. Mostly that boils down to two things I like in my code, re-usability\u00a0and&hellip;&nbsp;<a href=\"https:\/\/burnt-traces.com\/?p=29\" class=\"\" rel=\"bookmark\">Read More &raquo;<span class=\"screen-reader-text\">Create an Enum ComboBox in VB.Net<\/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":[11,14,15,88],"class_list":["post-29","post","type-post","status-publish","format-standard","hentry","category-vb-net","tag-combobox","tag-enum","tag-generics","tag-vb-net"],"_links":{"self":[{"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/posts\/29","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=29"}],"version-history":[{"count":1,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/posts\/29\/revisions"}],"predecessor-version":[{"id":331,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=\/wp\/v2\/posts\/29\/revisions\/331"}],"wp:attachment":[{"href":"https:\/\/burnt-traces.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=29"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=29"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/burnt-traces.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=29"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}