sabato 8 settembre 2007

un filtro veloce..

Quando mi capita di realizzare qualche gestionale, la richiesta che mi sento fare di più dai clienti è quella di poter lavorare senza staccare le mani dalla tastiera.. odiano il mouse. Per far fronte a tale richiesta, qualche tempo fa, ho realizzato uno UserControl facilmente riadattabile che permette la ricerca e la selezione di elementi ( ad esempio clienti, articoli etc etc ) all'interno di una DataGridView in modo molto rapido.

Nell'immagine qui in alto possiamo vedere una lista di clienti filtrata per "Codice Cliente" e "Nome Cliente". Mentre si digitano le parole chiave con le quali filtrare l'elenco di clienti, è possibile muoversi all'interno dell'elenco filtrato usando le freccie su e giù senza dover spostare il focus sulla DataGridView. A questo link potrete scaricare una soluzione vb.net 2005 contenente il codice delle UserControl. Qui brevemente mi limiterò ad illustrare le idee sulle quali si basa il filtro. Le due caselle di testo "Codice Cliente" e "Nome Cliente" sono il cuore del filtro, attraverso di esse si deve poter filtrare i clienti e contestualmente muoversi all'interno dell'elenco filtrato. Per ora puntiamo la nostra attenzione sulla parte di scorrimento e selezione del filtro. Entrambe le sopracitate caselle di testo sono istanze della classe bcc_TextBox, una classe che eredita da TextBox La classe bcc_TextBox contiene l'override della funzione ProcessCmdKey attraverso la quale è possibile intercettare la pressione di ogni tasto all'interno del controllo TextBox. I tasti che ci interessa intercettare e gestire sono ovviamente i tasti freccia SU e GIU e il tasto INVIO, per tutti gli altri vogliamo che la classe bcc_TextBox si comporti come un normale TextBox. Ecco il frammento di codice qui di seguito:

Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean

Select Case keyData

Case Keys.Down, Keys.Up, Keys.Return, Keys.Enter

RaiseEvent OneKeyPressed(keyData)
Return True

Case Else

Return MyBase.ProcessCmdKey(msg, keyData)

End Select

End Function

Come si può vedere dal codice, la classe bcc_TextBox lancia un evento OneKeyPressed per notificare all'esterno l'avvenuta pressione di uno dei tasti che si vuole gestire passando come parametro proprio il codice del tasto premuto. Sarà poi lo UserControl che si occuperà di gestire l'evento in questione attraverso il seguente handler:

Private Sub m_OneKeyPressed(ByVal key As System.Windows.Forms.Keys)

If IsNothing(dgv_Clienti.DataSource) Then Exit Sub

Dim cm As CurrencyManager
cm = Me.BindingContext(dgv_Clienti.DataSource)


If cm.Position = -1 Then Exit Sub

Select Case key

Case Keys.Up

If cm.Position = 0 Then
cm.Position = cm.List.Count - 1
Else
cm.Position -= 1
End If


Case Keys.Down

If cm.Position = cm.List.Count - 1 Then
cm.Position = 0
Else
cm.Position += 1
End If

Case Keys.Return, Keys.Enter

m_SelezionaCliente()

End Select

End Sub

Per spostarsi tra le righe del DataGridView si è usato un CurrencyManager, sfruttandone la proprietà Position è semplicissimo muoversi tra l'elenco filtrato dei clienti . Il CurrencyManager viene anche impiegato per restituire il cliente selezionato.

Private Sub m_SelezionaCliente()

Dim drv As DataRowView
Dim cm As CurrencyManager

cm = Me.BindingContext(dgv_Clienti.DataSource)
If cm.Position = -1 Then Exit Sub

drv = CType(cm.Current, DataRowView)

RaiseEvent ClienteSelezionato(drv("Id"), drv("Nome"))

End Sub

Resta da spiegare come avviene il filtraggio dei dati. Nessuna particolare novità, si è settato un evento TextChanged sulle due caselle di testo e si è composta una stringa con la quale filtrare il DataView usato come DataSource del DataGridView

Private Sub txt_DoFilter(ByVal sender As System.Object, ByVal e As System.EventArgs)

Try
RemoveHandler txt_CodiceCliente.TextChanged, AddressOf txt_DoFilter
RemoveHandler txt_NomeCliente.TextChanged, AddressOf txt_DoFilter

Dim dv As DataView
Dim strFilter As String = ""

dv = dgv_Clienti.DataSource

strFilter = ""

If txt_CodiceCliente.Text.Trim <> "" Then

Dim val As Int64

Try

val = CInt(txt_CodiceCliente.Text.Trim)

Catch ex As Exception

txt_CodiceCliente.Text = ""

Finally

strFilter = "( Id = " & txt_CodiceCliente.Text.Trim & " )"

End Try

End If

If txt_NomeCliente.Text.Trim <> "" Then

Dim tmp As String

tmp = txt_NomeCliente.Text.Trim
tmp = tmp.Replace("'", "")
tmp = tmp.Replace("""", "")
tmp = tmp.Replace("%", "")

If tmp <> txt_NomeCliente.Text.Trim Then txt_NomeCliente.Text = tmp

strFilter &= IIf(strFilter <> "", " AND ", "") & "(Nome Like '%" & txt_NomeCliente.Text.Trim & "%')"

End If

dv.RowFilter = strFilter
lb_ClientiTrovati.Text = dgv_Clienti.RowCount

Catch ex As Exception

Finally

AddHandler txt_CodiceCliente.TextChanged, AddressOf txt_DoFilter
AddHandler txt_NomeCliente.TextChanged, AddressOf txt_DoFilter

End Try

End Sub

Nessun commento: