Desenvolvimento - Visual Basic .NET
VB.NET: Implementando um DropdDownList com Sort e ItemDatabound()
Este artigo demonstra que com um pouco de criatividade, uso de herança e interfaces, podemos implementar recursos em controles já existente, tornando-os mais poderosos.
por Fernando Cerqueira- Construção de um Web Server Control
- Interface IComparer.
Este artigo usa as seguintes tecnologias:
- Visual Basic .NET
- Framework 1.1
Umas das coisas que mais me agradou quando conheci pela primeira vez o DataList e o DataGrid Control, foi o evento ItemDatabound(). Este evento foi exposto ao desenvolvedor para personalizar os Childs controls, registro a registro, dando a liberdade para implementar qualquer regra ou apresentação necessária aos dados antes de sua apresentação.
Infelizmente o Dropdownlist não possui esta facilidade. Muitas das vezes o leitor se depara com a necessidade de executar um DataBind() em uma DropDownList preenchendo a propriedade "Text" ou mesmo a "Value" com uma concatenação de mais de um campos ou mesmo interagindo com uma regra de negócio na aplicação. Um Exemplo simples seria popular o controle com as Cidades e UF juntas. Uma alternativa é retornar o resultado em objeto (DataReader, DataTable, Arrylist, etc.) e concatenar manualmente através de código. Outra alternativa, muito usada, é fazer esta "união" dentro da própria Query ou Store Procedure. Em Ambos os casos existem algumas desvantagens: Implementar uma interação extra dentro do código para atender nas necessidades; Criar Query" s específicas apenas para atender os casos de união, etc. Outra característica ausente é a ordenação durante o DataBind() ou mesmo um método exposto para este fim.
Resolvemos dar um fim nestas limitações, criando um DropdownlistExtend que realiza esta tarefa , compartilhando com leitor a solução neste artigo.
O Controle
Antes de mostrarmos o código, vamos definir o que desejamos do controle, e os cuidados para atender as novas características.
Primeiramente desejamos que nosso controle seja capaz de disparar um evento para cada item adicionado na lista, pelo comando DataBind(). Para termos esta característica é preciso dar um Override em OnDataBinding, assumindo o controle deste evento. Assumir o controle implica também em ser o mais abstrato possível com a origem do dado, pois ele pode vir em diversos tipos: OdbcDataReader , SqlDataReader, Colletions, DataTable etc.
O Evento disparado para aplicação devera possuir parâmetros para facilitar a manipulação do registro corrente e do item a ser adicionado. Desta forma, teremos como parâmetros:
Sender: objeto que originou o disparo. Tipo de dado: Object
Item: O item corrente a ser adicionado. Tipo de dado: Listitem
CurrentPosDataBound: O registro corrente. Tipo de dado: Object
Concluído, desejamos também que nosso controle execute a ordenação dos dados, seja pela propriedade "Text ou "Value". Os itens da dropdownlist ficam em uma colletion que por sua vez, não possui a interface IComparer. Para termos o Sort será criado uma classe que implemente a interface IComparer e que faça a comparação no tipo de dados ListItem.
Criando o Controle
Listagem 1. Criação da Classe DropdownListExtend Imports System.ComponentModel Imports System.Web.UI <ToolboxData("<{0}:DropdownListExtend runat=server></{0}:DropdownListExtend>")> _ Public Class DropdownListExtend Inherits System.Web.UI.WebControls.DropDownList Public Event ItemDataBound(ByVal sender As Object, _ ByVal Item As System.Web.UI.WebControls.ListItem, _ ByVal CurrentPosDataBound As Object) Public Enum TypeSort AscendText = 0 AscendValue = 1 DescendText = 2 DescendValue = 3 End Enum <DefaultValue(False), Category("Data")> _ Public Property AllowSort() As Boolean Get If viewstate("AllowSort") Is Nothing Then Return False End If Return CType(viewstate("AllowSort"), Boolean) End Get Set(ByVal Value As Boolean) viewstate("AllowSort") = Value End Set End Property <DefaultValue(GetType(TypeSort), "AscendText"), Category("Data")> _ Public Property SortType() As TypeSort Get If viewstate("SortType") Is Nothing Then Return TypeSort.AscendText End If Return CType(viewstate("SortType"), TypeSort) End Get Set(ByVal Value As TypeSort) viewstate("SortType") = Value End Set End Property Protected Overrides Sub OnDataBinding(ByVal e As System.EventArgs) ... ... End Sub Public Sub SortList() ... ... End Sub Private Class SortListClass ... ... End Class End Class
O controle DropdownlistExtend é criado herdando do controle Dropdownlist, sendo adicionado 2 propriedades, 1 método e 1 Evento :
AllowSort - Define se os dados serão ordenados após o Databind (True/False)
SortType - Define por qual campo será ordenado. Nesta propriedade usamos uma enumeração (TypeSort) com as possíveis combinações.
SortList - Método Sort exposto ao desenvolvedor para executar ordenação, caso seja incluídos novos itens após o DataBind().
ItemDataBound - Evento disparado para cada item que é adicionando na DropdownlistExtend durante o processo do método OnDataBinding. Note também que foi usado o Viewstate para persistir os dados das propriedades entre os postback que podem ocorrer na página que conterá o controle.
Listagem 2. Assumindo o controle do método OnDataBinding Protected Overrides Sub OnDataBinding(ByVal e As System.EventArgs) If Not DataSource Is Nothing Then If Me.DataTextField <> "" Or Me.DataValueField <> "" Then MyBase.OnDataBinding(e) Exit Sub End If If TypeOf DataSource Is IDataReader Then Dim Obj As IDataReader = CType(DataSource, IDataReader) While Obj.Read() Dim Item As New System.Web.UI.WebControls.ListItem RaiseEvent ItemDataBound(Me, Item, Obj) Me.Items.Add(Item) End While Obj.Close() ElseIf TypeOf DataSource Is IList Then Dim Obj As IList = CType(DataSource, IList) Dim Ind As Integer For Ind = 0 To Obj.Count - 1 Dim Item As New System.Web.UI.WebControls.ListItem RaiseEvent ItemDataBound(Me, Item, Obj(ind)) Me.Items.Add(Item) Next ElseIf TypeOf DataSource Is IEnumerable Then Dim Obj As IEnumerator = DataSource.GetEnumerator() Do While (Obj.MoveNext()) Dim Item As New System.Web.UI.WebControls.ListItem RaiseEvent ItemDataBound(Me, Item, Obj.Current) Me.Items.Add(Item) Loop ElseIf TypeOf DataSource Is IListSource Then Dim Obj As IList = CType(DataSource, IListSource).GetList Dim Ind As Integer For Ind = 0 To Obj.Count - 1 Dim Item As New System.Web.UI.WebControls.ListItem RaiseEvent ItemDataBound(Me, Item, Obj(ind)) Me.Items.Add(Item) Next Else MyBase.OnDataBinding(e) End If If AllowSort Then SortList() End If End If End Sub
Primeiro é verificado se uma das propriedades "DataTextField" ou "DataValueField" foram informadas. Caso uma destas propriedades contenha dados é executado normalmente o DataBind e não é disparado o evento ItemDataBound. Estando vazias, é feita uma verificação do Tipo de Dado que esta sendo processado na propriedade DataSource. Para termos a abstração necessária a verificação é centralizada na existência de interfaces que possibilitam interação registro a registro.
O único cuidado que o desenvolvedor deverá tomar é fazer a conversão correta do tipo de registro corrente, durante o tratamento do evento no aplicativo. Como exemplo podemos citar um cenário onde é passado um DataTable como fonte dos dados. Neste caso o evento ItemDataBound ira enviar para o aplicativo um DataRowView.
Ao final do Databind é verificado se a propriedade AllowSort esta habilitada e feita a ordenação em caso positivo (AllowSort = True).
Listagem 3. Fazendo o Sort dos dados. Public Sub SortList() Dim ArrItem(Me.Items.Count - 1) As System.Web.UI.WebControls.ListItem Me.Items.CopyTo(ArrItem, 0) Dim myComparer = New SortListClass(SortType) Array.Sort(ArrItem, myComparer) Me.Items.Clear() Dim Item As System.Web.UI.WebControls.ListItem For Each Item In ArrItem Me.Items.Add(Item) Next End Sub Private Class SortListClass Implements IComparer Private _TypeSortOrder As TypeSort Public Sub New() _TypeSortOrder = TypeSort.AscendText End Sub Public Sub New(ByVal Order As TypeSort) _TypeSortOrder = Order End Sub Function Compare(ByVal x As Object, ByVal y As Object) As Integer Implements IComparer.Compare If _TypeSortOrder = TypeSort.AscendText Then Return CType(x, System.Web.UI.WebControls.ListItem).Text < _ CType(y, System.Web.UI.WebControls.ListItem).Text ElseIf TypeSortOrder = TypeSort.DescendText Then Return CType(x, System.Web.UI.WebControls.ListItem).Text > _ CType(y, System.Web.UI.WebControls.ListItem).Text ElseIf TypeSortOrder = TypeSort.AscendValue Then Return CType(x, System.Web.UI.WebControls.ListItem).Value < _ CType(y, System.Web.UI.WebControls.ListItem).Value ElseIf TypeSortOrder = TypeSort.DescendValue Then Return CType(x, System.Web.UI.WebControls.ListItem).Value > _ CType(y, System.Web.UI.WebControls.ListItem).Value End If End Function End Class
Para execução do sort foi tirado proveito do método CopyTo que retornar um array com os itens de nossa dropdownlist . A classe Array tem a capacidade de ordenar seus elementos e possui em seu método de ordenação a opção de personalizar a comparação por uma classe que implemente a interface IComparer.
A criação da classe SortListClass implementa a interface necessária e faz a comparação de acordo com o tipo passado em seu construtor, sendo personalizado para comparação para o tipo ListItem.
Consumindo o Controle
Para consumir nosso controle basta que seja feita a compilação e inserido dentro da ToolBox a referência a DLL gerada (Clicando-se com o botão direito do mouse sobre a Toolbox e escolhendo a opção "Add/Remove Itens" ). Abaixo um Exemplo de código usando o evento ItemDatabound para mostrar o Estado e UF juntos usando como fonte de dados um DataTable.
Listagem 4. Usando o evento ItemDataBound Private Sub DropdownListExtend1_ItemDataBound(ByVal sender As Object, _ ByVal Item As System.Web.UI.WebControls.ListItem, _ ByVal CurrentPosDataBound As Object) Handles DropdownListExtend1.ItemDataBound Dim Obj As DataRowView = CType(CurrentPosDataBound, DataRowView) Item.Text = Obj.Item("uf_nome") & " - " & Obj.Item("uf") Item.Value = Obj.Item("uf") End Sub
Figura 1. O Controle e suas propriedades em Design mode.
Conclusões
Este artigo demonstra que com um pouco de criatividade, uso de herança e interfaces, podemos implementar recursos em controles já existente, tornando-os mais poderosos. Nunca o desenvolvedor teve uma plataforma tão rica em recursos como a plataforma .NET , e sabendo tirar proveito de seus recursos, poderá tornar o seu dia a dia cada vez produtivo e agradável.
- Entity Framework 4: Repositório GenéricoVisual Basic .NET
- As edições 14 da Easy .net Magazine e 88 da .net Magazine já estão disponíveis.ADO.NET
- Postando no Twiiter com .NET e Migre.meC#
- Setup ApplicationsVisual Basic .NET
- Problemas na manipulação de arquivos do MS Excel com .NETVisual Basic .NET