Laden...

[gelöst] WPF: Einträge in Listview auswählen

Erstellt von nordside vor 16 Jahren Letzter Beitrag vor 16 Jahren 6.120 Views
nordside Themenstarter:in
186 Beiträge seit 2007
vor 16 Jahren
[gelöst] WPF: Einträge in Listview auswählen

Hallo,

ich möchte per Code Einträge in einer ListView auswählen. Leider finde ich nur selectAll() für alles auswählen und SelectedIndex für den ersten zu markierenden Eintrag. Wie wähle ich aber den 2. ,4. und 5. Eintrag aus?

Ein listView.Items[index].Selected = true gibt es unter WPF nicht und listView.SelectedItems gibt nur Werte zurück - man kann selbst keien festlegen?

Was habe ich übersehen?
nordside

6.862 Beiträge seit 2003
vor 16 Jahren

Was habe ich übersehen?

Die Dependency Properties, bzw. in dem Sonderfall die Attached Properties.
Im konkreten Fall Selector.IsSelected auf true setzen und schon werden die Items selektiert angezeigt.

Baka wa shinanakya naoranai.

Mein XING Profil.

F
23 Beiträge seit 2007
vor 16 Jahren

Hi Talla,

Du kommst über den ItemsContainerGenerator an die ListViewItems ran. Die kannst Du dann auf IsSelected=True setzen:

ListView.SetIsSelected(Lv.ItemContainerGenerator.ContainerFromIndex(i), true);

Florian

www.planet-xaml.net

nordside Themenstarter:in
186 Beiträge seit 2007
vor 16 Jahren

Ich komme leider mit euren Hinweisen nicht zurecht.

Ich kann mit


listview.SetValue(ListView. ...)

auf Propertys zugreifen - leider finde kein Selector

was aber zu kompilieren geht, ist


ListView.SetIsSelected(
  listview.ItemContainerGenerator.ContainerFromIndex(2), true);

Bei der Ausführung wird aber eine WException geworfen

Der Wert darf nicht NULL sein.\r\nParametername: element" -
System.ArgumentNullException

Was mache ich da falsch? - Danke für Tipps
nordside

6.862 Beiträge seit 2003
vor 16 Jahren

Im Prinzip ist das ja nicht viel anders.

SetIsSelected erbt die ListView ja von Selector und die Funktion macht nichts anderes als auch wie ich, nämlich einfach das IsSelected Property für das DependencyObject das übergeben wird, zu setzen.

Dein Code hat den Vorteil dass man das ListViewItem wo der Content drin ist, nicht explizit kennen muss, sondern man sich das entsprechende automatisch generierte ListViewItem von der entsprechenden ListView holt und dann dort die Eigenschaft setzt.

Nachteilig ist das ganze aber für den Fall: Ich hab ne Menge von ListViewItems und weiß nicht zu welcher ListView sie gehören(Bsp. Zwei ListViews wo Items per D'n'D hin und her geschoben werden). Dann komm ich mit dem ItemContainerGenerator net weit.

Oki, das war jetzt beim Threadersteller anscheinend nicht der Fall, aber ich halte das direkte Setzen der Properties für universeller da ich keine Informationen über den Parent benötige.

Nur so als Ergänzung 😉

Baka wa shinanakya naoranai.

Mein XING Profil.

6.862 Beiträge seit 2003
vor 16 Jahren

Original von nordside
Ich komme leider mit euren Hinweisen nicht zurecht.

Ich kann mit

  
listview.SetValue(ListView. ...)  
  

auf Propertys zugreifen - leider finde kein Selector
nordside

Du musst das Property direkt bei den Items setzen. Also eher

ListViewItem1.SetValue(Selector.IsSelected,true);

Und Selector liegt im System.Windows.Controls.Primitives Namespace, vielleicht fehlt da einfach der Verweis wenn du keinen Selector von Intellisense(darauf würd ich mich eh noch net verlassen, zumindest in der Beta2 vom VS 2008 zeigt Intellisense in XAML lange net alles an was wirklich geht) angeboten bekommst.

Baka wa shinanakya naoranai.

Mein XING Profil.

F
23 Beiträge seit 2007
vor 16 Jahren

ArgumentNullException - Was mache ich da falsch?

Wahrscheinlich rufst Du die Methode zum falschen Zeitpunkt auf und die Items sind noch gar nicht vorhanden.
Tipps: mal nen Breakpoint setzen und myListView.Items.Count prüfen. Falls die Items noch nicht vorhanden sind. Je nachdem wann du die Items füllst, würde ich z.B. den Loaded Event vor dem Selektieren abwarten.

Florian

www.planet-xaml.net

nordside Themenstarter:in
186 Beiträge seit 2007
vor 16 Jahren

Hallo

@talla

du hast in Deinem Beitrag ListViewItem1 geschrieben. Daher gehe ich davon aus, dass man das Objekt nimmt und nicht die statische Klasse. Ich versuchte


listview.Items[0].SetValue(Selector.IsSelected, true);

bekomme aber eine Fehlermeldung

'object' does not contain a definition for 'SetValue' and no extension method 'SetValue' accepting a first argument of type 'object' could be found (are you missing a using directive or an assembly reference?)

Den Namespace System.Windows.Controls.Primitives habe ich aber eingebunden. Verwende ich die Klasse ListViewItem finde ich kein Property Selector oder eine Methode SetIsSelected.

@fkruesch

Bevor ich die Einräge im Quelltext markieren möchte, füge ich diese per


listview.Items.Add("item5");

hinzu. Sie werden auch angezeigt. Nur das markieren funktioniert nicht. Ich habe auch den SelectionMode auf Extended gesetzt.

Bin immer noch ratlos 🙁
nordside

F
23 Beiträge seit 2007
vor 16 Jahren

Bevor ich die Einräge im Quelltext markieren möchte, füge ich diese ... hinzu

Das reicht aber nicht. Die Items (Daten-Objekte) sind dann zwar vorhanden, aber noch keine ListViewItems, die selektiert werden können.

Also, wie gesagt, passende Events abwarten:

lv.LayoutUpdated += delegate
            {
                ListViewItem item1 = (ListViewItem)lv.ItemContainerGenerator.ContainerFromIndex(0);
                item1.IsSelected = true;
            };

            lv.Items.Add(1);

Florian

www.planet-xaml.net

6.862 Beiträge seit 2003
vor 16 Jahren

bekomme aber eine Fehlermeldung

Ja, diese Fehlermeldung hat nichts mit WPF zu tun, sondern die gibts schon so lang wies .Net gibt. Deine ItemCollection gibt dir nen Object zurück und kein ListViewItem, du müsstest also einfach auf ListViewItem casten und dann könntest du das so machen wie ich vorgeschlagen hab. Das wird bei dir aber net gehen 🙂

Da du keine ListViewItems explizit in deiner ListView einfügst, sondern ja nur Strings(bei deinem Beispiel), wird dir Items[0] auch nur nen string zurückgeben. Der Trick ist jetzt, dass dieser String intern ja aber trotzdem in ein ListViewItem eingefügt wurde von der ListView, und um dieses Item erstmal zu bekommen müsstest du die Funktion die fkruesch vorgeschlagen hat mit dem ItemContainerGenerator nutzen. Dann würdest du dein ListViewItem bekommen und dort könntest du dann entweder auf meine Art direkt mit SetValue oder wie fkruesch es vorgeschlagen hat mit ListView.SetIsSelected setzen.

Verwende ich die Klasse ListViewItem finde ich kein Property Selector oder eine Methode SetIsSelected.

Selector ist auch kein Property sondern eine Klasse und Selector.IsSelectedProperty ist ein attached Property das benutzt wird um den Selektionsstatus zu speichern. Das ich immer Selector.IsSelected geschrieben hab ist mein Fehler 🙁 Weil das gibts auch, aber das it dann nur nen klassisches Property das das attached Property wrappt, für SetValue brauch man direkt das Attached Property.

Und SetIsSelected ist keine Methode von ListViewItem, sondern von der ListView direkt das sie von Selector vererbt bekommen hat.

Eigentlich gibts ja auch noch ne dritte und wahrscheinlich einfachste Variante wenn man Dependency/Attached Properties nicht so mag:

Wenn du dein ListViewItem hast(wo du des herbekommst findest du oben beschrieben), dann kannst du auch direkt das IsSelected Property von ListView setzen 🙂

Baka wa shinanakya naoranai.

Mein XING Profil.

nordside Themenstarter:in
186 Beiträge seit 2007
vor 16 Jahren

Ich bin jetzt einigermaßen verwirrt X( - deshalb einmal Schritt für Schritt

  1. Problem ist, dass ich durch

lv.Items.Add("item5");

nur Items, aber keine ListViewItems hinzufüge? Aber Add() erwartet als Parameter ein object - damit bekommt die ListView doch nicht mit, was ich einfüge String, ListViewItem, StackPanel, ...

  1. Wenn ich also einen Eintrag markieren möchte, muss ich zunächst tatsächlich ein ListViewItem nehmen. Das sollte so funktionieren:

ListViewItem item1 = (ListViewItem)lv.ItemContainerGenerator.ContainerFromIndex(1);

Bei mir liefert das null, obwohl lv.Items.Count den Wert 5 hat. Ich habe versucht die Anweisung erfolgreich nach dem LayoutUpdate-Ereignis, als auch direkt nach dem hinzufügen der Items auszuführen - immer kommt nur null.

Mein Quelltext sieht im Moment so aus:


lv.SelectionMode = SelectionMode.Extended;
lv.LayoutUpdated += delegate
{
  ListViewItem item1 = (ListViewItem)lv.ItemContainerGenerator.ContainerFromIndex(0);
  item1.IsSelected = true;
};

for(int i=0; i<5; i++)
{
  ListViewItem lvi = new ListViewItem();
  lvi.Content = "item"+i;
  lv.Items.Add(lvi);
}

lv.Focus();

nordside

F
23 Beiträge seit 2007
vor 16 Jahren

Die ListViewItems werden automatisch erzeugt und die Items als Content dort reingepackt.
Das hier ist also überflüssig:


ListViewItem lvi = new ListViewItem();  
lvi.Content = "item"+i;

Versucht es doch mal so:

lv.ItemContainerGenerator.StatusChanged += delegate
            {
                if (lv.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) return;

                ListViewItem lvItem = (ListViewItem)lv.ItemContainerGenerator.ContainerFromIndex(0);
                lvItem.IsSelected = true;
            };

            lv.Items.Add(1);
            lv.Items.Add(2);
            lv.Items.Add(3);

Florian

www.planet-xaml.net

nordside Themenstarter:in
186 Beiträge seit 2007
vor 16 Jahren

Die gute Nachricht: es funktioniert. Man kann auch das Event LayoutUpdated nutzen.

Durch


if (lv.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated)
{
  return;
}

wird verhindert, dass mit null-Werten anschließend hantiert wird. Wie wird der Status vom ItemContainerGenerator aber geändert?

Ausserdem wird das LayoutUpdated unabhängig von der Anzahl der Items 4mal ausgeführt. Die ersten beiden male wird die Selektion erfüllt - dann können die Items selektiert werden. Kann man das erklären?

Vielen Dank
nordside

F
23 Beiträge seit 2007
vor 16 Jahren

LayoutUpdated war eine schlechte Wahl - der wird jedesmal geworfen, wenn das Layout upgedated wird 🙂 Das passiert z.B. auch bei Resize oder wenn sich die Grösse des Panels ändert etc.

Der Status des ItemContainerGenerator wird von der WPF "Engine" im Hintergrund geändert... Du wirfst in die Items Collection irgendwelche Objekte rein und WPF erzeugt dann die entsprechenden ListViewItems als Container für die Objekte.
Das Ganze wird im Hintergrund etwas verzögert, z.B. damit es nicht bei jedem Items.Add erfolgt sondern in einem Rutsch.
Meistens werden die Items ja über DataBinding der ItemsSource gesetzt.

Florian

www.planet-xaml.net

nordside Themenstarter:in
186 Beiträge seit 2007
vor 16 Jahren

Super - es funktioniert! Event wird jetzt wirklich nur zweimal ausgelöst. Einmal wenn der Status noch nicht "ContainersGenerated" ist, aber danach mit Erfolg.

Noch einmal vielen Dank für Eure Hilfe talla und Florian
nordside