.NET Tip #11: Vlastní komponenta DropDownEnumList

Tomáš Jecha, MVP, MCSD       10.10.2008       C#, VB.NET, .NET Tips       11010 zobrazení

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:

Toolbox

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í:

Formulář s upraveným ComboBox

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í.

 

hodnocení článku

2 bodů / 2 hlasů       Hodnotit mohou jen registrované uživatelé.

 

Nový příspěvek

 

Super

Akurát take niečo som hľadal

nahlásit spamnahlásit spam 0 odpovědětodpovědět
                       
Nadpis:
Antispam: Komu se občas házejí perly?
Příspěvek bude publikován pod identitou   anonym.

Nyní zakládáte pod článkem nové diskusní vlákno.
Pokud chcete reagovat na jiný příspěvek, klikněte na tlačítko "Odpovědět" u některého diskusního příspěvku.

Nyní odpovídáte na příspěvek pod článkem. Nebo chcete raději založit nové vlákno?

 

  • Administrátoři si vyhrazují právo komentáře upravovat či mazat bez udání důvodu.
    Mazány budou zejména komentáře obsahující vulgarity nebo porušující pravidla publikování.
  • Pokud nejste zaregistrováni, Vaše IP adresa bude zveřejněna. Pokud s tímto nesouhlasíte, příspěvek neodesílejte.

přihlásit pomocí externího účtu

přihlásit pomocí jména a hesla

Uživatel:
Heslo:

zapomenuté heslo

 

založit nový uživatelský účet

zaregistrujte se

 
zavřít

Nahlásit spam

Opravdu chcete tento příspěvek nahlásit pro porušování pravidel fóra?

Nahlásit Zrušit

Chyba

zavřít

feedback