jueves, 2 de julio de 2020

Listbox con elementos de apariencia diferente

El control Listbox de Windows Forms es bastante útil en determinadas situaciones y muy utilizado también. Una característica que puede ser poco conocida para algunos desarrolladores es la posibilidad de definir las características de cada línea (elemento) mostrada en este control de forma independiente.
Este resultado se puede lograr de un modo bastante sencillo realizando 3 simples pasos:
  - En primer lugar debemos establecer la propiedad DrawMode al valor OwnerDrawFixed o el valor OwnerDrawVariable.
  - En segundo lugar, hay que definir el manejador del evento DrawItem. Aquí podremos dibujar lo que queremos mostrar en cada línea del Listbox de forma individual para cada elemento. Es posible definir el color, tamaño y familia de la fuente, por ejemplo.
  - En último lugar, y sólo en caso de haber seleccionado la opción DrawMode = OwnerDrawVariable, debemos definir el manejador del evento MeasureItem que nos permitirá variar las dimensiones de la línea que ocupa cada elemento de la fuente de datos del ListBox.

A continuación se muestra un poco de código con un ejemplo de lo arriba descrito. En el código se puede ver una clase auxiliar que se utiliza para definir cada uno de los elementos que muestra el control Listbox. En esta clase se incluye la propiedad Fuente que nos permite definir la fuente del texto mostrado en cada línea del control de forma independiente.

Public Class frmFuentes
    Private Const FUENTE_MIN As Integer = 8
    Private Const FUENTE_MAX As Integer = 14
    Dim listaFuentes As List(Of ItemCboFuentes)

    Private Sub frmFuentes_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Dim fuentesInstaladas As New InstalledFontCollection
        Dim strFamiliasFuentes As New StringBuilder("")
        Dim itemCombo As ItemCboFuentes
        listaFuentes = New List(Of ItemCboFuentes)
        Dim valor As Integer = 0
        For Each familia In fuentesInstaladas.Families
            If valor Mod 2 = 0 Then
                itemCombo = New ItemCboFuentes(familia.Name, valor.ToString())
            Else
                itemCombo = New ItemCboFuentes(familia.Name, valor.ToString(), FUENTE_MAX)
            End If
            listaFuentes.Add(itemCombo)
            valor = valor + 1
        Next
        cboFuente.ValueMember = "Valor"
        cboFuente.DisplayMember = "Texto"
        cboFuente.DataSource = listaFuentes
        lstFuentes.DrawMode = DrawMode.OwnerDrawVariable
        lstFuentes.ValueMember = "Valor"
        lstFuentes.DisplayMember = "Texto"
        lstFuentes.DataSource = listaFuentes
    End Sub

    Private Sub cboFuente_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboFuente.SelectedIndexChanged
        MessageBox.Show("Text: " & cboFuente.SelectedItem.ToString() & " -- " & cboFuente.SelectedValue)
    End Sub

    Private Sub ListBox1_DrawItem(sender As Object, e As DrawItemEventArgs) Handles lstFuentes.DrawItem
        Dim indice As Integer = e.Index
        Dim rectF As RectangleF
        rectF = RectangleF.op_Implicit(e.Bounds)
        e.DrawBackground()
        e.Graphics.DrawString(listaFuentes.Item(indice).Texto, listaFuentes.Item(indice).Fuente, Brushes.Black, RectangleF.op_Implicit(e.Bounds))
        e.DrawFocusRectangle()
    End Sub

    Private Sub lstFuentes_MeasureItem(sender As Object, e As MeasureItemEventArgs) Handles lstFuentes.MeasureItem
        If e.Index Mod 2 <> 0 Then
            e.ItemHeight = e.ItemHeight * 2
        End If
    End Sub

    'Clase auxiliar para definir los elementos que vamos a mostrar en el control Listbox.
    'Esta clase incluye una propiedad Fuente que nos permite definir la fuente de cada br/>     'elemento de forma independiente.
    Private Class ItemCboFuentes
        Private _texto As String
        Public Property Texto() As String
            Get
                Return _texto
            End Get
            Set(ByVal value As String)
                _texto = value
            End Set
        End Property
        Private _valor As String
        Public Property Valor() As String
            Get
                Return _valor
            End Get
            Set(ByVal value As String)
                _valor = value
            End Set
        End Property
        Private _fuente As Font
        Public Property Fuente() As Font
            Get
                Return _fuente
            End Get
            Set(ByVal value As Font)
                _fuente = value
            End Set
        End Property
        Sub New()
            Texto = ""
            Valor = ""
            Fuente = New Font(FontFamily.GenericSansSerif, FUENTE_MIN)
        End Sub

        Sub New(ByVal texto As String, ByVal value As String)
            _texto = texto
            _valor = value
            _fuente = New Font(texto, FUENTE_MIN)
        End Sub

        Sub New(ByVal texto As String, ByVal value As String, ByVal tam As Integer)
            _texto = texto
            _valor = value
            _fuente = New Font(texto, tam)
        End Sub
    End Class

End Class

El código mostrado permite obtener el resultado que se observa en la siguiente imagen.


No hay comentarios:

Publicar un comentario