Vyhledávání položek v ListView   zodpovězená otázka

VB.NET, WinForms

Mám problém s vyhledáváním v komponentě ListView. Našel jsem na stránkách zdroják, ale nevím na co ho mám vázat aby se po nalezení textu označil řádek s položkou.

Poradtě někdo prosím. Možná by stálo za to udělat na to nějaký seriál.

'Visual Basic (Declaration)
Public Function FindItemWithText ( _
    text As String, _
    includeSubItemsInSearch As Boolean, _
    startIndex As Integer _
) As ListViewItem

'Visual Basic (Usage)
Dim instance As ListView
Dim text As String
Dim includeSubItemsInSearch As Boolean
Dim startIndex As Integer
Dim returnValue As ListViewItem

returnValue = instance.FindItemWithText(text, _
    includeSubItemsInSearch, startIndex)


'nebo

'deklarace
Public Function FindItemWithText ( _
    text As String _
) As ListViewItem

‘kód po deklaraci
Dim instance As ListView
Dim text As String
Dim returnValue As ListViewItem

returnValue = instance.FindItemWithText(text)


nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Zkuste to navázat...

Neni-li returnValue nothing,tak

returnValue.selected=true

mate-li povolen multiselect,tak

příp. projit selecteditems cyklem

a zrusit predchozi vybrané položky.

za zmínku snad stoji také :

returnValue.EnsureVisible()

aby se listview přerolovalo

na Vámi nalezenou položku.

Snad to pomůže...

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Díky moc, zkusím to.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Hledá to, ale řádek to neoznačí. Když to slovo tam je, tak to nic nedělá a když tam není tak to vypíše nenalezeno.

Co s tím? Kde dělám chybu?


Public Class Form1
    Public Function FindItemWithText(ByVal text As String, ByVal includeSubItemsInSearch As Boolean, ByVal startIndex As Integer) As ListViewItem
        
    End Function


'______________________________________________________________
Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Dim instance As ListView
        Dim text As String
        Dim includeSubItemsInSearch As Boolean
        Dim startIndex As Integer
        Dim returnValue As ListViewItem
        text = TextBox1.Text
        instance = ListView1
        startIndex = 0
        includeSubItemsInSearch = False
        returnValue = instance.FindItemWithText(Text, includeSubItemsInSearch, startIndex)
        If returnValue Is Nothing Then
            MsgBox("Nenalezeno", MsgBoxStyle.Exclamation)
        Else
            returnValue.Selected = True
        End If
    End Sub

Za odpověď díky.

Pavel

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Už to hledá, ale nastal další problém s tím, že když je v tabulce víc stejných slov, tak to ty další nenajde.

Pro správný běh se musí nastavit hodnota v properties ListView

HideSelection na False

    Private Sub Button4_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button4.Click
        Dim instance As ListView
        Dim text As String
        Dim includeSubItemsInSearch As Boolean
        Dim startIndex As Integer
        Dim returnValue As ListViewItem
        text = TextBox1.Text
        instance = ListView1
        startIndex = 0
        includeSubItemsInSearch = True
        returnValue = instance.FindItemWithText(text, includeSubItemsInSearch, startIndex)
        If returnValue Is Nothing Then
            MsgBox("Nenalezeno", MsgBoxStyle.Critical)
        Else
            returnValue.Selected() = True

        End If

Jak mám napsat aby se hledalo další slovo od nalezeného???

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Zkuste tohle

    Private foundAtIndex As Integer

    Private Sub Button_Find_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_Find.Click
        foundAtIndex = FindItemWithText(ListView1, TextBox1.Text, 0)
    End Sub

    Private Sub Button_FindNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_FindNext.Click
        If foundAtIndex + 1 >= ListView1.Items.Count Then
            MessageBox.Show("Jste na konci")
        Else
            foundAtIndex = FindItemWithText(ListView1, TextBox1.Text, foundAtIndex + 1)
        End If
    End Sub

    Private Function FindItemWithText(ByVal lv As ListView, ByVal text As String, ByVal startIndex As Integer, Optional ByVal subItemsText As Boolean = True) As Integer
        Dim foundItem As ListViewItem = lv.FindItemWithText(text.Trim, subItemsText, startIndex)

        If foundItem IsNot Nothing Then

            For Each item As ListViewItem In lv.Items
                item.Selected = False
            Next

            foundItem.Selected = True

            Return foundItem.Index
        Else

            MessageBox.Show("Nenalezeno")

        End If

    End Function

neměl jsem čas to moc testovat, ale snad by to mohlo fungovat

nahlásit spamnahlásit spam 3 / 3 odpovědětodpovědět

Je to lepší než to moje, ale hlásí to chybu:

Error 1 Handles clause requires a WithEvents variable defined in the containing type or one of its base types.

opravil jsem

Private Sub Button_FindNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button_Find.Click

a chybu to nepíše, ale další slovo nenajde.

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Nevím čeho přesně chcete dosáhnout, ale zdá se mi, že to je další případ pokusu o použití komponenty k něčemu, k čemu nebyla navržena...

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Jde mi jen o to, aby když zadám do textboxu jméno, aby mi v ListView označil řádek s hledaným jménem. Pokud hledané jméno je v ListView obsaženo dvakrát, tak aby po dalším stisknutí tlačítka se označení přesunulo na další jméno. To je celé. Myslím, že to ListView zvládne ale bohužel nevím jak toho mám dosáhnout.

Pavel

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Předchozí příspěvek byl perfektní,

lze třeba i jen jedním tlačítkem...

A stačí přidat EnsureVisible viz. výše

Private Function FindItemWithText(ByVal lv As ListView, ByVal text As String, ByVal startIndex As Integer, Optional ByVal subItemsText As Boolean = True) As Integer
        Dim foundItem As ListViewItem = lv.FindItemWithText(text.Trim, subItemsText, startIndex)

        If foundItem IsNot Nothing Then
            For Each item As ListViewItem In lv.SelectedItems
                item.Selected = False
            Next

            foundItem.Selected = True
            foundItem.EnsureVisible()
            Return foundItem.Index
        Else
            MessageBox.Show("Nenalezeno")
        End If
    End Function
    

    Private Sub btnFindAndFindNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFindAndFindNext.Click
        Dim startFrom As Integer = IIf(foundAtIndex > 0, foundAtIndex + 1, 0)
        foundAtIndex = FindItemWithText(lv, TextBox1.Text, startFrom)
        btnFindAndFindNext.Text = IIf(foundAtIndex = 0, "Find", "Find next")
    End Sub

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Opravte si ,prosím, název tlačítka a události,

taky za lv ve funkci váš název listview...

Co zkusit datagrid(view) plus filter

a budete hledat i v konkrétním sloupci...

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Díky za pomoc. Jsi génius :-)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

No a proč to tedy neuděláte ručně procházením položek ListView komponenty v cyklu?

Private _index As Integer
Private Sub Search_Click(sender As Object, e As EventArgs) Handles Search.Click
  Dim upperBound = ListView1.Items.Count - 1
  If _index = upperBound Then
    'Jestliže byla dosažena poslední položka,
    'začít hledat od začátku.
     _index = 0
  End If
  For x = _index To upperBound
    Dim item = ListView1.Items(x)
    If item.Text = TextBox1.Text Then
      item.EnsureVisible()
      item.Selected = True
      _index = x + 1
      Exit For
    End If
  Next
End Sub

Aby to správně fungovalo, musí mít ListView nastaveno MultiSelect = False a HideSelection = False.

nahlásit spamnahlásit spam 2 / 2 odpovědětodpovědět

Správný postup:

----------------

Do deklarační části vložit

    Dim foundAtIndex As Integer



    Private Function FindItemWithText(ByVal lv As ListView, ByVal text As String, ByVal startIndex As Integer, Optional ByVal subItemsText As Boolean = True) As Integer
        Dim foundItem As ListViewItem = lv.FindItemWithText(text.Trim, subItemsText, startIndex)

        If foundItem IsNot Nothing Then
            For Each item As ListViewItem In lv.SelectedItems
                item.Selected = False
            Next

            foundItem.Selected = True
            foundItem.EnsureVisible()
            Return foundItem.Index
        Else
            MessageBox.Show("Vyhledávané slovo není v seznamu.")
        End If

    End Function

Potom do událostí Textboxu a Tlačítka(Buttonu) vložit

    Private Sub TextBox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles TextBox1.KeyDown
        If e.KeyCode = Keys.Enter Then
            e.Handled = True

            On Error Resume Next
            Dim startFrom As Integer = IIf(foundAtIndex > 0, foundAtIndex + 1, 0)
            foundAtIndex = FindItemWithText(ListView1, TextBox1.Text, startFrom)
            btnFindAndFindNext.Text = IIf(foundAtIndex = 0, "Další", "Hledat další")

        End If
    End Sub

    Private Sub TextBox1_GotFocus(ByVal sender As Object, ByVal e As System.EventArgs) Handles TextBox1.GotFocus
        foundAtIndex = 0
        btnFindAndFindNext.Text = "Hledat"
    End Sub

    Private Sub btnFindAndFindNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFindAndFindNext.Click
        On Error Resume Next
        Dim startFrom As Integer = IIf(foundAtIndex > 0, foundAtIndex + 1, 0)
        foundAtIndex = FindItemWithText(ListView1, TextBox1.Text, startFrom)
        btnFindAndFindNext.Text = IIf(foundAtIndex = 0, "Další", "Hledat další")
    End Sub

Doufám, že to někomu dalšímu taky pomůže v řešení tohoto problému. :)

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Děkuji za příspěvky. Konečný výsledek hledání v ListView je od neznámého autora který dodal zdroják za který moc děkuji.

Postup:

Před Form.Load - jako deklaraci vložte funkci

Private Function FindItemWithText(ByVal lv As ListView, ByVal text As String, ByVal startIndex As Integer, Optional ByVal subItemsText As Boolean = True) As Integer
        Dim foundItem As ListViewItem = lv.FindItemWithText(text.Trim, subItemsText, startIndex)

        If foundItem IsNot Nothing Then
            For Each item As ListViewItem In lv.SelectedItems
                item.Selected = False
            Next

            foundItem.Selected = True
            foundItem.EnsureVisible()
            Return foundItem.Index
        Else
            MessageBox.Show("Nenalezeno")
        End If
    End Function

Přidejte tlačítko a změňte název na btnFindAndFindNext a doplňte kód

Private Sub btnFindAndFindNext_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnFindAndFindNext.Click
        Dim foundAtIndex As Integer
        Dim startFrom As Integer = IIf(foundAtIndex > 0, foundAtIndex + 1, 0)
        foundAtIndex = FindItemWithText(ListView1, TextBox1.Text, startFrom)
        btnFindAndFindNext.Text = IIf(foundAtIndex = 0, "Find", "Find next")
    End Sub

To je vše. Funguje sqvěle.

Můj problém byl vyřešen. Moc Vám všem děkuji za pomoc.

nahlásit spamnahlásit spam 1 / 1 odpovědětodpovědět

Pardon, ale obávám se, že :

Dim foundAtIndex As Integer

mělo být v deklarační části

formuláře nikoliv v události

kliknutí na tlačítko jinak bude

vyhledáván stále první výskyt

hledaného textu... Co myslíte?

Dík za funkci patří právem Honzovi!

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Máš pravdu Honzíku. Děkuji

nahlásit spamnahlásit spam 0 odpovědětodpovědět

To je omyl Honza je autorem

té první vyhledávací funkce.

Možná by bylo pěkné místo procházení

položky v listview rovnou filtrovat...

Založte nový projekt windowsapplication

a vložte kód do Form1:


Public Class Form1

    Dim lv As DataListView, dt As DataTable
    Dim tb As TextBox, cb As ComboBox

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        lv = New DataListView
        tb = New TextBox
        cb = New ComboBox
        cb.DropDownStyle = ComboBoxStyle.DropDown
        Dim pnl As Panel = New Panel
        With pnl
            .Controls.Add(cb)
            .Controls.Add(tb)
            tb.Left = cb.Width
            .Height = tb.Height
        End With

        Me.Controls.Add(lv)
        lv.Location = New System.Drawing.Point(0, pnl.Height)
        lv.Dock = DockStyle.Fill
        Me.Controls.Add(pnl)
        pnl.Dock = DockStyle.Top
        AddHandler cb.SelectedIndexChanged, New EventHandler(AddressOf cb_SelectedIndexChanged)
        AddHandler tb.TextChanged, New EventHandler(AddressOf tb_TextChanged)

        dt = New DataTable
        dt.Columns.Add("Jméno")
        dt.Columns.Add("Příjmení")

        dt.Rows.Add("Honza", "Dufek")
        dt.Rows.Add("Pavel", "Dufek")
        dt.Rows.Add("Jan", "Hlávka")
        dt.Rows.Add("Milan", "Dufek")
        dt.Rows.Add("Jan", "Duffon")
        dt.Rows.Add("Pavel", "Hlávka")
        dt.Rows.Add("Ondřej", "Linhart")
        dt.Rows.Add("Mirek", "Linhart")

        lv.SetDataSource(dt)

        For Each c As DataColumn In dt.Columns
            lv.Columns.Add(c.Caption)
            cb.Items.Add(New String(c.Caption))
        Next

        cb.SelectedIndex = 0
    End Sub

    Private Sub cb_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
        tb.Clear()
    End Sub

    Private Sub tb_TextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
        If tb.Text = vbNullString Then
            lv.SetDataSource(dt)
        Else
            Dim tbFilter As New DataTable
            tbFilter = dt.Clone
            Dim flt As String
            flt = cb.Text & " Like '" & tb.Text & "%'"
            Dim dr() As DataRow = dt.Select(flt)
            For i As Integer = 0 To dr.Length - 1
                tbFilter.ImportRow(dr(i))
            Next
            lv.SetDataSource(tbFilter)
        End If
    End Sub
End Class

Public Class DataListView
    Inherits ListView

    Public Sub SetDataSource(ByVal fromDataTable As DataTable)
        Me.Items.Clear()

        For i As Integer = 0 To fromDataTable.Rows.Count - 1
            Dim lvItem As ListViewItem
            lvItem = Me.Items.Add(fromDataTable.Rows(i).Item(0).ToString)
            For j As Integer = 1 To fromDataTable.Columns.Count - 1
                lvItem.SubItems.Add(fromDataTable.Rows(i).Item(j).ToString)
            Next j
        Next i

    End Sub

    Public Sub New()
        Me.View = Windows.Forms.View.Details
        Me.HideSelection = False
        Me.GridLines = True
    End Sub
End Class

Zdraví Gábina

nahlásit spamnahlásit spam 5 / 5 odpovědětodpovědět

Promiň Gábinko, hned to vyzkouším. Dík patří hlavně tobě :-)

nahlásit spamnahlásit spam 0 odpovědětodpovědět

Pěkný, ale filtrování se mi nelíbí. To tvoje procházení položek bylo lepší.

Pavel

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