[VB.NET] Listview find resultaat in andere listview

Pagina: 1
Acties:
  • 326 views sinds 30-01-2008
  • Reageer

  • mrfatmen
  • Registratie: Februari 2001
  • Laatst online: 08:47
Ik zit weer eens met een volgens mij simpel probleem.

ik heb een listview (merktabel) welke merken van autos bevat,
een listview (plaats_list2) welke leeg is
en een textbox welke we meegeven als woord.

Het is de bedoeling dat als ik in de textbox iets zet, dat er in plaats_list2 de merken komen te staan welke in merktabel voldoen aan de text in de textbox.

voorbeeld:
Als ik in de textbox "ford" in geef moet er in plaats_list2 "bedford, ford, ford usa" komen te staan

Nu heb ik daar de volgende routine voor bedacht:
Visual Basic .NET:
1
2
3
4
5
6
7
8
9
10
11
12
Private Sub MerkFilterList1(ByRef woord As TextBox)
  Dim items() As ListViewItem
  Plaats_list2.Items.Clear()

  items = merktabel.Items.Find(woord.Text, False)
  Plaats_list2.Items.AddRange(items.Clone)

  If Plaats_list2.Items.Count = 0 Then
   woord.Text = woord.Text.Remove(woord.Text.Length - 1)
   woord.SelectionStart = woord.Text.Length
  End If
 End Sub


Enkel als ik deze draai krijg ik de volgende fout op regel 6 (hierboven):
Cannot add or insert the item 'ALFA ROMEO' in more than one place.
You must first remove it from its current location or clone it.
Parameter name: item
Wat volgens mij komt omdat hij items als reference heeft meegenomen.
Maar omdat ik hem clone zal het volgens mij mening moeten werken.

Maak ik hier een denk fout?


Ik weet dat ik het als volgt kan oplossen.
Wat bijna de zelfde techniek is enkel is het loopje vertragend.
(Nu gebruik ik een tabel van z'n 130 merken, maar de zelfde techniek moet gaan werken voor 1 a 2 duizend items in een tabel.)
Visual Basic .NET:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Private Sub MerkFilterList1(ByRef woord As TextBox)
  Dim items() As ListViewItem
  Plaats_list2.Items.Clear()


  items = merktabel.Items.Find(woord.Text, False)
  For Each itm As ListViewItem In items
   Plaats_list2.Items.Add(itm.Clone)
  Next


  If Plaats_list2.Items.Count = 0 Then
   woord.Text = woord.Text.Remove(woord.Text.Length - 1)
   woord.SelectionStart = woord.Text.Length
  End If
 End Sub



Dus mijn vraag nog een specifiek
Maak ik gewoon een grove denk fout?
En wat kan ik doen om toch de snelheid er een beetje in te houden?

Heeft uw auto pijn? Ga dan naar de onderdelenlijn
Het bedrijf waar ik met veel plezier werk - Mijn eigen vertrouwde domein


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 26-04 09:25

pjvandesande

GC.Collect(head);

Visual Basic .NET:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Private Sub MerkFilterList1(ByRef woord As TextBox) 
  Dim items() As ListViewItem 
  Plaats_list2.Items.Clear() 


  items = merktabel.Items.Find(woord.Text, False) 
  For Each itm As ListViewItem In items 
   itm.Remove()
   Plaats_list2.Items.Add(itm.Clone()) 
  Next 


  If Plaats_list2.Items.Count = 0 Then 
   woord.Text = woord.Text.Remove(woord.Text.Length - 1) 
   woord.SelectionStart = woord.Text.Length 
  End If 
 End Sub


Zou moeten werken.

[ Voor 17% gewijzigd door pjvandesande op 06-10-2005 14:41 ]


  • mrfatmen
  • Registratie: Februari 2001
  • Laatst online: 08:47
dat werkt inderdaad.
maar dat is nog steeds vrij traag.

Is daar niet iets aan te doen

Heeft uw auto pijn? Ga dan naar de onderdelenlijn
Het bedrijf waar ik met veel plezier werk - Mijn eigen vertrouwde domein


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 26-04 09:25

pjvandesande

GC.Collect(head);

Haal de Clone weg, zie ik nu pas trouwens.

Ik zou alles asynchroon gaan doen dmv Threads. Verder zou je een profiler kunnen pakken om bottlenecks te zoeken en vinden.

  • whoami
  • Registratie: December 2000
  • Nu online
Ipv ieder ListViewItem apart aan de ListView toe te voegen, kan je eens proberen om ze eerst in een arraylist te zetten, en dan, alle items in één keer aan de listview toe te voegen door gebruik te maken van de AddRange method:

code:
1
listView1.Items.AddRange ((ListViewItem[])myArrayList.ToArray(typeof(ListViewItem)))


Kijk ook eens naar de BeginUpdate() en EndUpdate methods (al denk ik dat die automatisch door AddRange worden opgeroepen)

[ Voor 17% gewijzigd door whoami op 06-10-2005 14:56 ]

https://fgheysels.github.io/


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 26-04 09:25

pjvandesande

GC.Collect(head);

whoami schreef op donderdag 06 oktober 2005 @ 14:55:
Ipv ieder ListViewItem apart aan de ListView toe te voegen, kan je eens proberen om ze eerst in een arraylist te zetten, en dan, alle items in één keer aan de listview toe te voegen door gebruik te
AddRange send wel een Message, maar dit is volgens mij alleen maar om de Item array te laten groeien en verder doet die niets anders dan een for loop waar hij de items er 1 voor 1 in dondert.

[ Voor 9% gewijzigd door pjvandesande op 06-10-2005 15:02 ]


  • whoami
  • Registratie: December 2000
  • Nu online
Ik zou zeggen, test het eens uit. ;)

Daarnaast zorgen de Begin- en EndUpdate methods er ook voor dat de ListView niet iedere keer opnieuw een paint event krijgt, waardoor de performance ook omhoog gaat.

https://fgheysels.github.io/


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 26-04 09:25

pjvandesande

GC.Collect(head);

whoami schreef op donderdag 06 oktober 2005 @ 15:06:
Ik zou zeggen, test het eens uit. ;)
Dit doet AddRange:
C#:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public void AddRange(ListViewItem[] values)
{
      if (values == null)
      {
            throw new ArgumentNullException("values");
      }
      IComparer comparer1 = this.owner.listItemSorter;
      this.owner.listItemSorter = null;
      try
      {
            if (this.owner.IsHandleCreated)
            {
                  this.owner.SendMessage(0x102f, (int) (this.Count + values.Length), 0);
            }
            ListViewItem[] itemArray1 = values;
            for (int num1 = 0; num1 < itemArray1.Length; num1++)
            {
                  ListViewItem item1 = itemArray1[num1];
                  this.Add(item1);
            }
      }
      finally
      {
            this.owner.listItemSorter = comparer1;
      }
      if ((comparer1 != null) || (this.owner.Sorting != SortOrder.None))
      {
            this.owner.Sort();
      }
}

  • whoami
  • Registratie: December 2000
  • Nu online
En daaraan kan je zien dat een AddRange sneller is dan dat je zelf iedere keer Add gaat gaan oproepen (als je ook zelf deze acties niet onderneemt).

Er wordt geen sortering toegepast na iedere Add.
Welke message wordt daar trouwens gestuurd ?

Ik dacht toch ook dat er in de help stond dat AddRange beginupdate en endupdate aanroept ? Blijkbaar niet...
Dat moet je dus ook nog zelf ff doen.

https://fgheysels.github.io/


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 26-04 09:25

pjvandesande

GC.Collect(head);

whoami schreef op donderdag 06 oktober 2005 @ 15:48:
En daaraan kan je zien dat een AddRange sneller is dan dat je zelf iedere keer Add gaat gaan oproepen (als je ook zelf deze acties niet onderneemt).

Er wordt geen sortering toegepast na iedere Add.
Er word inderdaad niet na elk Item gesorteerd.
Welke message wordt daar trouwens gestuurd ?
Deze message zorgt ervoor dat de array groeit, indien nodig naar het aantal totale items na het toevoegen van je items.
Denk aan een Grow functie van een ArrayList.
Ik dacht toch ook dat er in de help stond dat AddRange beginupdate en endupdate aanroept ? Blijkbaar niet...
Dat moet je dus ook nog zelf ff doen.
Ik kan dit niet vinden in een help, ik zie het wel is bij sommige tutorials staan maar die vertrouw ik vaak toch niet :)

[ Voor 3% gewijzigd door pjvandesande op 06-10-2005 16:10 ]


  • whoami
  • Registratie: December 2000
  • Nu online
Ik ook niet meer. :P
The preferred way to add multiple items to a ListView is to use the AddRange method of the ListView.ListViewItemCollection (accessed through the Items property of the ListView). This enables you to add an array of items to the list in a single operation. However, if you want to add items one at a time using the Add method of the ListView.ListViewItemCollection class, you can use the BeginUpdate method to prevent the control from repainting the ListView each time an item is added. Once you have completed the task of adding items to the control, call the EndUpdate method to enable the ListView to repaint. This way of adding items can prevent flickered drawing of the ListView when a large number of items are being added to the control.

https://fgheysels.github.io/


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 26-04 09:25

pjvandesande

GC.Collect(head);

Overigens vind ik het ook wel vreemd dat de AddRange method dit niet doet.

  • mrfatmen
  • Registratie: Februari 2001
  • Laatst online: 08:47
oke, ik doe blijkbaar wat fout.
find deed niet precies wat ik wou.

Waardoor ik volgens mij dus met een loopje door alle items heen moet stappen.
Maar voor een tabel van 1400 items duurt het ruim 3 sec voor hij de tabel doorlopen is.
Wat niet zou hoeven, dus lijkt mij dat dit niet de meest efficente methode.

Dus wie kan mij op weg helpen op de sneller te vinden.

Probleem stelling:
(1) ik heb een listview met items (1400), dit is de basis tabel.
(2) ik heb een listview waarin de mogelijkheden moeten komen te staan
(3) Ik heb een textbox welke het filter is.

Als ik 1 letter in de textbox(3) zet moet er in de listview(2) alle items uit listview(1) komen te staan welke dat letter bevatte.

wat ik nu gebruik is gewoon te traag.
Visual Basic .NET:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
Private Sub DelenFilterList1(ByRef woord As TextBox)
  Plaats_List.Items.Clear()
  Plaats_List.Text = ""
  Console.WriteLine("Run")

  Plaats_list.BeginUpdate()
  For Each itm As ListViewItem In deeltabel.Items
   If InStr(itm.Text, woord.Text, CompareMethod.Text) <> 0 Then
    Plaats_list.Items.Add(itm.Text)

    Application.DoEvents()
   End If
  Next
  Plaats_list.EndUpdate()

  Console.WriteLine("check")
  If Plaats_List.Items.Count = 0 Then
   woord.Text = woord.Text.Remove(woord.Text.Length - 1)
   woord.SelectionStart = woord.Text.Length
  End If
 End Sub

[ Voor 4% gewijzigd door mrfatmen op 06-10-2005 17:11 ]

Heeft uw auto pijn? Ga dan naar de onderdelenlijn
Het bedrijf waar ik met veel plezier werk - Mijn eigen vertrouwde domein


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 26-04 09:25

pjvandesande

GC.Collect(head);

Application.DoEvents vertraagt helemaal.

Gooi zoals whoami al aangeeft eerst alles in een ArrayList oid en donder het pas daarna in een ListView.

  • mrfatmen
  • Registratie: Februari 2001
  • Laatst online: 08:47
doevents heb ik nu weg gehaald en scheelt iets.
Maar als ik de add weglaat en alleen het loopen door de items laat lopen,
kost het ook al 2 sec voor dat hij er doorheen is.

Ik denk daarom dat ik daar al fout ga maar weet zo even geen snellere manier.
Wat zou ik anders kunnen doen om mijn doel te bereiken zonder door de items heen te loopen.

Heeft uw auto pijn? Ga dan naar de onderdelenlijn
Het bedrijf waar ik met veel plezier werk - Mijn eigen vertrouwde domein


  • whoami
  • Registratie: December 2000
  • Nu online
Het loopen door 1000 items zou op zich niet veel tijd in beslag mogen nemen.
Ik denk dat dit één van de boosdoeners is:
code:
1
 If InStr(itm.Text, woord.Text, CompareMethod.Text)

https://fgheysels.github.io/


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 26-04 09:25

pjvandesande

GC.Collect(head);

mrfatmen schreef op donderdag 06 oktober 2005 @ 17:16:
doevents heb ik nu weg gehaald en scheelt iets.
Maar als ik de add weglaat en alleen het loopen door de items laat lopen,
kost het ook al 2 sec voor dat hij er doorheen is.

Ik denk daarom dat ik daar al fout ga maar weet zo even geen snellere manier.
Wat zou ik anders kunnen doen om mijn doel te bereiken zonder door de items heen te loopen.
Pak is een profiler, daarmee kun je precies ziet hoelang statements duren.
Maar veel van deze dingen doe ik altijd asynchroon.

  • mrfatmen
  • Registratie: Februari 2001
  • Laatst online: 08:47
ok, asynchroon is nieuw voor mij, zou je dat een toe kunnen lichten.

Heeft uw auto pijn? Ga dan naar de onderdelenlijn
Het bedrijf waar ik met veel plezier werk - Mijn eigen vertrouwde domein


  • whoami
  • Registratie: December 2000
  • Nu online
Waarom maak je gebruik van een oude VB method (Instr)?
Waarom maak je geen gebruik van de mogelijkheden die de String class in .NET je biedt ?
Waarom maak je bv geen gebruik van de IndexOf member functie van string ?
Maar veel van deze dingen doe ik altijd asynchroon.
Dat versnelt het niet, verhoogt enkel de responsiviteit, in sommige gevallen.

https://fgheysels.github.io/


  • pjvandesande
  • Registratie: Maart 2004
  • Laatst online: 26-04 09:25

pjvandesande

GC.Collect(head);

mrfatmen schreef op donderdag 06 oktober 2005 @ 17:20:
ok, asynchroon is nieuw voor mij, zou je dat een toe kunnen lichten.
Je gaat je find method uitvoeren in een anderen Thread. Met ResetEvents kun je wat wachten op dingen en via Events gooi je wat info als je een Item hebt gevonden.

Zoek maar is op Thread's of bekijk de Thread class is met wat voorbeelden.
Pagina: 1