V dnešním příspěvku ukážu, jak si napsat komponentu odvozenou z rozbalovacího seznamu ComboBoxu, která dokáže zobrazovat položky výčtu Enum.
Budeme chtít, aby měl vlasnost EnumType, které předáme typ výčtu. V příkladu to bude výčet Ovoce:
VB.NET:
Public Enum Ovoce
Hruska
Banan
Jablko
Pizza
End Enum
C#:
public enum Ovoce
{
Hruska, Banan, Jablko, Pizza
}
Následně pak bude obsahovat vlastnost SelectedEnumValue, ze které lze zjistit nebo nastavit hodnotu položky výčtu, která je vybrána. Ostatní vlastnosti a funkce zůstavají stejné jako v ComboBox.
Kód prvku přidáme do nového souboru do projektu. Ve Visual Basicu je:
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Text
Namespace WindowsFormsApplication1
Class DropDownEnumList
Inherits System.Windows.Forms.ComboBox
Public Sub New()
MyBase.New()
End Sub
Private m_enumType As Type
''' <summary>
''' Vrací nebo nastavuje typ výčtu, který se bude zobrazovat
''' </summary>
<System.ComponentModel.Browsable(False)> _
Public Property EnumType() As Type
Get
Return m_enumType
End Get
Set(ByVal value As Type)
If value Is Nothing OrElse value.IsEnum Then
If m_enumType Is value Then
Return
End If
' naplnit položky seznamu
m_enumType = value
FillItems()
Else
Throw New ArgumentException("Vlastnost EnumType musí být přiřazen typ výčtu Enum.")
End If
End Set
End Property
''' <summary>
''' Vrací nebo nastavuje vybranou položku výčtu
''' </summary>
<System.ComponentModel.Browsable(False)> _
Public Property SelectedEnumValue() As Object
Get
' není přiřazen EnumType
If EnumType Is Nothing Then
Return Nothing
End If
' není vybrána položka ze seznamu
If Me.SelectedItem Is Nothing OrElse SelectedItem.GetType() IsNot GetType(ItemEnumType) Then
Return Nothing
End If
' vrátit hodnotu
Return DirectCast(Me.SelectedItem, ItemEnumType).Value
End Get
Set(ByVal value As Object)
' není přiřazen EnumType
If EnumType Is Nothing Then
Return
End If
' projít položky
For Each i As Object In Me.Items
' zjistit jestli je zvolená položka v seznamu
If i.GetType() Is GetType(ItemEnumType) AndAlso [Enum].GetName(EnumType, value) = DirectCast(i, ItemEnumType).Field.Name Then
' vybrat zvolenou položku
Me.SelectedItem = i
Return
End If
Next
End Set
End Property
''' <summary>
''' Naplní seznam položkama
''' </summary>
Protected Sub FillItems()
Items.Clear()
If EnumType Is Nothing Then
Return
End If
For Each field As System.Reflection.FieldInfo In From n In [Enum].GetNames(EnumType) _
Select EnumType.GetField(n)
Items.Add(New ItemEnumType(field))
Next
End Sub
''' <summary>
''' Třída pro uchování seznamu
''' </summary>
Protected Class ItemEnumType
''' <summary>
''' Konstruktor položky výčtu
''' </summary>
''' <param name="field"></param>
Public Sub New(ByVal field As System.Reflection.FieldInfo)
Me.Field = field
End Sub
Private _field As System.Reflection.FieldInfo
''' <summary>
''' Hodnota z výčtu
''' </summary>
Public Property Field() As System.Reflection.FieldInfo
Get
Return _field
End Get
Private Set(ByVal value As System.Reflection.FieldInfo)
_field = value
End Set
End Property
''' <summary>
''' Hodnota položky
''' </summary>
Public ReadOnly Property Value() As Object
Get
Return Field.GetRawConstantValue()
End Get
End Property
''' <summary>
''' Textová reprezentace
''' </summary>
''' <returns></returns>
Public Overloads Overrides Function ToString() As String
Return Me.Field.Name
End Function
End Class
End Class
End Namespace
A v C#:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WindowsFormsApplication1
{
class DropDownEnumList : System.Windows.Forms.ComboBox
{
public DropDownEnumList()
: base()
{
}
private Type enumType;
/// <summary>
/// Vrací nebo nastavuje typ výčtu, který se bude zobrazovat
/// </summary>
[System.ComponentModel.Browsable(false)]
public Type EnumType
{
get
{
return enumType;
}
set
{
if (value == null || value.IsEnum)
{
if (enumType == value)
return;
// naplnit položky seznamu
enumType = value;
FillItems();
}
else
{
throw new ArgumentException("Vlastnost EnumType musí být přiřazen typ výčtu Enum.");
}
}
}
/// <summary>
/// Vrací nebo nastavuje vybranou položku výčtu
/// </summary>
[System.ComponentModel.Browsable(false)]
public object SelectedEnumValue
{
get
{
// není přiřazen EnumType
if (EnumType == null)
return null;
// není vybrána položka ze seznamu
if (this.SelectedItem == null || this.SelectedItem.GetType() != typeof(ItemEnumType))
return null;
// vrátit hodnotu
return ((ItemEnumType)this.SelectedItem).Value;
}
set
{
// není přiřazen EnumType
if (EnumType == null)
return;
// projít položky
foreach (object i in this.Items)
{
// zjistit jestli je zvolená položka v seznamu
if (i.GetType() == typeof(ItemEnumType) && Enum.GetName(EnumType, value) == ((ItemEnumType)i).Field.Name)
{
// vybrat zvolenou položku
this.SelectedItem = i;
return;
}
}
}
}
/// <summary>
/// Naplní seznam položkama
/// </summary>
protected void FillItems()
{
Items.Clear();
if (EnumType == null)
return;
foreach (System.Reflection.FieldInfo field in from n in Enum.GetNames(EnumType) select EnumType.GetField(n))
{
Items.Add(new ItemEnumType(field));
}
}
/// <summary>
/// Třída pro uchování seznamu
/// </summary>
protected class ItemEnumType
{
/// <summary>
/// Konstruktor položky výčtu
/// </summary>
/// <param name="field"></param>
public ItemEnumType(System.Reflection.FieldInfo field)
{
this.Field = field;
}
/// <summary>
/// Hodnota z výčtu
/// </summary>
public System.Reflection.FieldInfo Field
{
get;
private set;
}
/// <summary>
/// Hodnota položky
/// </summary>
public object Value
{
get
{
return Field.GetRawConstantValue();
}
}
/// <summary>
/// Textová reprezentace
/// </summary>
/// <returns></returns>
public override string ToString()
{
return this.Field.Name;
}
}
}
}
Všimněte se, že ve tříde dědící z ComboBoxu je i druhá třída ItemEnumType. Ta přepisuje ToString() a tak definuje jak bude položka v seznamu textově zobrazena. Zároveň v sobě třída drží hodnotu položky výčtu, aby mohla identifikovat snadno zvolenou hodnotu.
Když takový projekt rebuildujeme (menu Build / Rebuild solution), objeví se nám prvek v toolboxu:
Po umístění na formulář přidáme navíc 2 tlačíka. Jedno na otestování vybrané hodnoty a druhé na její nastavení:
Kód testovacího formuláře je pak následující (všimněte si, že v konstruktoru třídy nastavuji EnumType na typ výčtu Ovoce):
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Namespace WindowsFormsApplication1
Public Partial Class Form1
Inherits Form
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' nastavit hodnotu
dropDownEnumList1.EnumType = GetType(Ovoce)
End Sub
Private Sub btnZjistiHodnotu_Click(sender As Object, e As EventArgs)
' zobrazit hlasku k vybranemu ovoci
If dropDownEnumList1.SelectedEnumValue IsNot Nothing Then
Dim vybraneOvoce As Ovoce = DirectCast(dropDownEnumList1.SelectedEnumValue, Ovoce)
Dim hlaska As String = String.Empty
Select Case vybraneOvoce
Case Ovoce.Hruska
hlaska = "hrušky"
Exit Select
Case Ovoce.Banan
hlaska = "banány"
Exit Select
Case Ovoce.Jablko
hlaska = "jablíčka"
Exit Select
Case Ovoce.Pizza
hlaska = "pizzy. To ale není ovoce"
Exit Select
End Select
MessageBox.Show(String.Format("Vypadá to, že máš rád {0}!", hlaska))
End If
End Sub
Private Sub btnNastavJablko_Click(sender As Object, e As EventArgs)
' nastavit jednu hodnotu
dropDownEnumList1.SelectedEnumValue = Ovoce.Jablko
End Sub
End Class
Public Enum Ovoce
Hruska
Banan
Jablko
Pizza
End Enum
End Namespace
A v C#:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
// nastavit hodnotu
dropDownEnumList1.EnumType = typeof(Ovoce);
}
private void btnZjistiHodnotu_Click(object sender, EventArgs e)
{
// zobrazit hlasku k vybranemu ovoci
if (dropDownEnumList1.SelectedEnumValue != null)
{
Ovoce vybraneOvoce = (Ovoce)dropDownEnumList1.SelectedEnumValue;
string hlaska = string.Empty;
switch (vybraneOvoce)
{
case Ovoce.Hruska:
hlaska = "hrušky";
break;
case Ovoce.Banan:
hlaska = "banány";
break;
case Ovoce.Jablko:
hlaska = "jablíčka";
break;
case Ovoce.Pizza:
hlaska = "pizzy. To ale není ovoce";
break;
}
MessageBox.Show(string.Format("Vypadá to, že máš rád {0}!", hlaska));
}
}
private void btnNastavJablko_Click(object sender, EventArgs e)
{
// nastavit jednu hodnotu
dropDownEnumList1.SelectedEnumValue = Ovoce.Jablko;
}
}
public enum Ovoce
{
Hruska, Banan, Jablko, Pizza
}
}
V kódu vidíme jak snadno nastavit hodnotu přímo z výčtu ovoce a také jak vybranou hodnotu získat. Věřím, že se kód může hodit i v praktickém používání.