WPF ListBox in ListBox



  • Moin,

    folgendes Szenario mag ich simulieren.
    Ich brauche in einer Listbox eine weitere Listbox. Fast wie eine List in einer List.Weil für ein Element mehrere Unterelemente existieren können.
    Aktuell habe ich folgendes Problem.Ich kann die Listbox in der Listbox nicht im Code ansprechen um den ItemsSource zu setzen.
    Momentan sieht der Xaml-Code so aus:

    <ListBox x:Name="listbox_uebersicht" DockPanel.Dock="Right" Margin="5 5 5 5" Padding="5 5 5 5" >
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <ListBox x:Name="listbox_elemente">
                            <ListBox.ItemTemplate>
                                <DataTemplate>
                                        <Border CornerRadius="4 0 4 0" BorderThickness="2" BorderBrush="Aquamarine" Padding="4 4 4 4">
                                        <StackPanel>
                                            <TextBlock Text="{Binding StartDatum}" FontSize="14" FontStyle="Italic" />                            
                                        <StackPanel Orientation="Horizontal">
                                        <Border CornerRadius="4 0 4 0" BorderThickness="2" BorderBrush="Aquamarine" Padding="4 4 4 4">
                                           <StackPanel>
                                                <TextBlock Text="{Binding TransaktionsArt}"/>
                                                <TextBlock Text="{Binding Betrag}"/>
                                                <TextBlock Text="{Binding Beschreibung}"/>
                                         </StackPanel>
                                        </Border>                                     
                                       </StackPanel>
                                    </StackPanel>
                                    </Border>
                                </DataTemplate>
                            </ListBox.ItemTemplate>
                           </ListBox>
                        </DataTemplate>
                    </ListBox.ItemTemplate>            
                 </ListBox>
    

    Kann mir jemand sagen wie ich das beschriebene erreichen kann?Evneutell durch eine elegantere Lösung oder über den aktuellen Weg?


  • Administrator

    Firefighter schrieb:

    Ich kann die Listbox in der Listbox nicht im Code ansprechen um den ItemsSource zu setzen.

    Kannst du den Satz ein wenig mehr erläutern? In welchem Code, C# oder XAML? Sind die Bindings in der ListBox der ListBox das Problem, bzw. dass sie nicht funktionieren?
    Halt einfach ein wenig genauer, wo das eigentliche Problem liegt 😉

    Grüssli



  • ansprechen brauchst du es denk ich nicht - da du den datacontext vermutlich auf eine liste hast kannst du diese liste direkt binden

    ich vermute du hast im code bereits eine liste in der liste ?

    (ich spaare mir mal implementations details - das meiste wirst du schon kennen

    public class Item
    {
        public ObservableCollection<Item> Items = new ObservableCollection<Item>();
    }
    
    public class Window
    {
        private ObservableCollection<Item> Items = new ObservableCollection<Item>();
        public Window()
        {
            MyList.DataContext = Items;
        }
    }
    
    <Window>
        <ListView ItemSource="{Binding Items}"> <-- Items in Window
            <ListView.View>
                <GridView>
                    <GridViewColumn>
                        <GridViewColumn.CellTemplate>
                            <ListView ItemSource="{Binding Items}"> <-- Items von jedem Item , da das DataContext bereits auf Items ist
                        </GridViewColumn.CellTemplate>
                    </GridViewColumn>
                </GridView>
            </ListView.View>
        </ListView>
    </Window>
    

    oh

    ich seh grad du redest von einer listbox - da muesste es simlutan gehen wenn du das ItemSource per binding setzt



  • Sorry Dravere, hast natürlich Recht.Also eigentlich geht es um folgendes.
    Es gibt Transaktionen(Ausgaben,Einnahme,Sonstige Ausgaben).
    Pro Tag kann es natürlich mehrere dieser Transaktionen geben, so nun wollte ich diese Menge an Transaktionen pro Tag irgendwie darstellen, also dachte ich mir, ich nehm eine Listbox, packe dort den aktuellen Tag rein, welcher als unterelemente ebend weitere Listboxen hat, mit den Transaktionen.Fals jemand eine bessere Idee hat, wie man das visualisieren könnte, immer her damit.
    @mr evil, auf deinen Rat habe ich nur gewartet :p.
    Die Idee scheint nicht schlecht, und wie du es richtig erfasst habe, ich hatte schon eine Liste erstellt.Aber ich schau mir mal deine Lösung genauer an.
    Danke.

    edit:@mr evil, das mit dem ListView ist natürlich wesentlich eleganter.



  • Soo ich hab nun eine etwas bessere Variante. Nur so richtig scheint es nicht zu klappen, anscheint Binded er nicht richtig. Hier mal mein XAML Code und der C# Code

    <ListView ItemsSource="{Binding Path=Items}" x:Name="listview">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Datum" DisplayMemberBinding="{Binding Path=StartDatum}"/>
                        <GridViewColumn Header="Betrag" DisplayMemberBinding="{Binding Path=Betrag}"/>
                        <GridViewColumn Header="Beschreibung" DisplayMemberBinding="{Binding Path=Beschreibung}"/>
                        <GridViewColumn Header="Art" DisplayMemberBinding="{Binding Path=TransaktionsArt}"/>
                    </GridView>
                </ListView.View>
            </ListView>
    
    public Mainform()
            {
                InitializeComponent();
                Transaktion aktion1 = new Transaktion(Transaktion.Art.Sonstige, DateTime.Now);
                aktion1.Beschreibung = "test1";
                aktion1.Betrag = 100;
                Transaktion aktion2 = new Transaktion(Transaktion.Art.Ausgabe, DateTime.Now);
                aktion2.Beschreibung = "test2";
                aktion2.Betrag = 200;
                Transaktion aktion3 = new Transaktion(Transaktion.Art.Einnahme, DateTime.Now);
                aktion3.Beschreibung = "test3";
                aktion3.Betrag = 300;
    
                ObservableCollection<Transaktion> Items = new ObservableCollection<Transaktion>();
    
                Items.Add(aktion1);
                Items.Add(aktion2);
                Items.Add(aktion3);
    
                listview.DataContext = Items;            
    
            }
    

    Kann mir jemand sagen wo der Fehler liegt?



  • Nur so richtig scheint es nicht zu klappen, anscheint Binded er nicht richtig.

    Etwas spezifischer ?


  • Administrator

    Firefighter schrieb:

    Kann mir jemand sagen wo der Fehler liegt?

    Schau mal ganz genau, wo Mr Evil die Variable Items deklariert/definiert und wie er das Binding realisiert hat. Bei dir sieht das jedenfalls ziemlich anders aus und mit dem was du zeigst, kann ich mir nicht vorstellen, dass dies funktionieren wird.

    Zudem, wie ist das eigentlich, wäre nicht Name die richtige Eigenschaft, statt x:Name um einen Namen für das Objekt zu definieren? x:Name ist doch nur für Ressourcen gedacht.

    Grüssli



  • Sorry Knuddlbaer, hast Recht, vergesses jedes mal. Der Binded in dem Sinne nicht Richtig, das er die Daten einfach nicht anzeigt.
    @Dravere. Ich glaube ist egal ob x:Name oder Name, beides ist möglich.



  • Hmm @Dravere, so auf Anhieb weiß ich nicht was an meinem Falsch sein soll, ich meine ich setze den Datacontext von der Listview auf meine Collection, binde diese dann im XAML, um dann auf die einzelene Komponenten der Collection in meinen GridViewColums zuzgreifen, steh etwas aufem schlauch. 😕


  • Administrator

    <ListView ItemsSource="{Binding}" x:Name="listview"><!-- Nur {Binding} -->
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Datum" DisplayMemberBinding="{Binding Path=StartDatum}"/>
                <GridViewColumn Header="Betrag" DisplayMemberBinding="{Binding Path=Betrag}"/>
                <GridViewColumn Header="Beschreibung" DisplayMemberBinding="{Binding Path=Beschreibung}"/>
                <GridViewColumn Header="Art" DisplayMemberBinding="{Binding Path=TransaktionsArt}"/>
            </GridView>
        </ListView.View>
    </ListView>
    

    Und ja, so sieht auch der Code von Mr Evil nicht aus. Ich hätte allerdings gedacht, dass dieser auch funktionieren würde, tut er aber nicht, nachdem ich es selber getestet habe 🙂

    Der C# Code bleibt übrigens unverändert.

    Grüssli



  • Korrekt, mein XAML Code sieht nun genauso aus, und mein C# Code sieht nun folgender MAßen aus.

    public class Item
        {
            public ObservableCollection<Transaktion> Items = new ObservableCollection<Transaktion>();
        }
    
        public partial class Mainform : Window
        {
            private ObservableCollection<Item> Items = new ObservableCollection<Item>();
            public Mainform()
            {
                InitializeComponent();
    
                Transaktion aktion1 = new Transaktion(Transaktion.Art.Sonstige, DateTime.Now);
                aktion1.Beschreibung = "test1";
                aktion1.Betrag = 100;
                Transaktion aktion2 = new Transaktion(Transaktion.Art.Ausgabe, DateTime.Now);
                aktion2.Beschreibung = "test2";
                aktion2.Betrag = 200;
                Transaktion aktion3 = new Transaktion(Transaktion.Art.Einnahme, DateTime.Now);
                aktion3.Beschreibung = "test3";
                aktion3.Betrag = 300;
    
                Item item = new Item();
                item.Items.Add(aktion1);
                item.Items.Add(aktion2);
                item.Items.Add(aktion3);
    
                Items.Add(item);
    
                listview.DataContext= Items;
            }
        }
    

    Entspricht doch dem wie es Mr evil jebaut hatte oder irre ich mich?



  • Dravere schrieb:

    Und ja, so sieht auch der Code von Mr Evil nicht aus. Ich hätte allerdings gedacht, dass dieser auch funktionieren würde, tut er aber nicht, nachdem ich es selber getestet habe 🙂

    is doch logisch
    ich hab das binding explizit zu einer liste gesetzt da ich davon aus ging das die daten in einer viewmodel im datacontext des fensters sitzen , dann bindet man auf ein feld der viewmodel
    wenn man aber im code behind des fensters arbeitet und den datacontext der liste setzt kanns ja nicht funktionieren

    denn wenn der datacontext auf der liste ist , und das itemssource auf Items - sucht er Items _in_ der observablecollection , das ist natuerlich kaese fuer die hauptliste - dann kommt ein konstrukt das er Items in Items in Items sucht #gg

    der code veraendert sich sozusagen leicht wenn man entweder mit der code behind arbeitet oder mit mvvm

    hier mal beide varianten: (natuerlich hier im forum ausn kopf geschrieben , muss nicht funktionieren {o;)

    MainView.xaml

    <ListView ItemsSource="{Binding Items}"> <!-- die Items liste aus der MainViewModel vom DataContext des fensters -->
        <ListView.View>
            <GridView>
                <GridViewColumn>
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <ListView ItemsSource="{Binding Items}" x:Name="listview"> <!-- die Items von der Item klasse -->
                                <ListView.View>
                                    <GridView>
                                        <GridViewColumn Header="Datum" DisplayMemberBinding="{Binding Path=StartDatum}"/>
                                        <GridViewColumn Header="Betrag" DisplayMemberBinding="{Binding Path=Betrag}"/>
                                        <GridViewColumn Header="Beschreibung" DisplayMemberBinding="{Binding Path=Beschreibung}"/>
                                        <GridViewColumn Header="Art" DisplayMemberBinding="{Binding Path=TransaktionsArt}"/>
                                    </GridView>
                                </ListView.View>
                            </ListView> 
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>
    

    Item.cs

    public class Item
    {
        public ObservableCollection<Transaktion> Items = new ObservableCollection<Transaktion>();
    }
    

    MainViewModel.cs

    class MainViewModel
    {
        private ObservableCollection<Item> Items = new ObservableCollection<Item>();
        public MainViewModel()
        {
            Transaktion aktion1 = new Transaktion(Transaktion.Art.Sonstige, DateTime.Now);
            aktion1.Beschreibung = "test1";
            aktion1.Betrag = 100;
            Transaktion aktion2 = new Transaktion(Transaktion.Art.Ausgabe, DateTime.Now);
            aktion2.Beschreibung = "test2";
            aktion2.Betrag = 200;
            Transaktion aktion3 = new Transaktion(Transaktion.Art.Einnahme, DateTime.Now);
            aktion3.Beschreibung = "test3";
            aktion3.Betrag = 300;
    
            Item item = new Item();
            item.Items.Add(aktion1);
            item.Items.Add(aktion2);
            item.Items.Add(aktion3);
    
            Items.Add(item);
        }
    }
    

    App.cs

    protected overrice OnStartup()
    {
        MainView view = new MainView();
        view.DataContext = new MainViewModel(); // <-- darum geht das {Binding Items} der ersten liste
        view.Show();
        base.OnStartup();
    }
    

    wenn man in der code behind ist , also ohne mvvm arbeitet , und das datacontext zu der liste gibt muss man das binding leicht anpassen wie dravere das auch gemacht hat , sonst ist der code identisch

    MainView.xaml

    <ListView ItemsSource="{Binding}" x:Name="myList"> <!-- die Items werden gefunden da DataContext explizit gesetzt -->
        <ListView.View>
            <GridView>
                <GridViewColumn>
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <ListView ItemsSource="{Binding Items}" x:Name="listview"> <!-- die Items von der Item klasse -->
                                <ListView.View>
                                    <GridView>
                                        <GridViewColumn Header="Datum" DisplayMemberBinding="{Binding Path=StartDatum}"/>
                                        <GridViewColumn Header="Betrag" DisplayMemberBinding="{Binding Path=Betrag}"/>
                                        <GridViewColumn Header="Beschreibung" DisplayMemberBinding="{Binding Path=Beschreibung}"/>
                                        <GridViewColumn Header="Art" DisplayMemberBinding="{Binding Path=TransaktionsArt}"/>
                                    </GridView>
                                </ListView.View>
                            </ListView> 
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
            </GridView>
        </ListView.View>
    </ListView>
    

    Item.cs

    public class Item
    {
        public ObservableCollection<Transaktion> Items = new ObservableCollection<Transaktion>();
    }
    

    MainView.xaml.cs

    class MainViewModel
    {
        private ObservableCollection<Item> Items = new ObservableCollection<Item>();
        public MainViewModel()
        {
            Transaktion aktion1 = new Transaktion(Transaktion.Art.Sonstige, DateTime.Now);
            aktion1.Beschreibung = "test1";
            aktion1.Betrag = 100;
            Transaktion aktion2 = new Transaktion(Transaktion.Art.Ausgabe, DateTime.Now);
            aktion2.Beschreibung = "test2";
            aktion2.Betrag = 200;
            Transaktion aktion3 = new Transaktion(Transaktion.Art.Einnahme, DateTime.Now);
            aktion3.Beschreibung = "test3";
            aktion3.Betrag = 300;
    
            Item item = new Item();
            item.Items.Add(aktion1);
            item.Items.Add(aktion2);
            item.Items.Add(aktion3);
    
            Items.Add(item);
    
            myList.DataContext = Items;
        }
    }
    

  • Administrator

    @Firefighter,
    Willst du eigentlich immernoch eine Liste in einer Liste haben? Wäre es nicht sinnvoller alles in eine ListView zu packen, eine weitere Kolonne dazu, welches das Datum der Überweisung beinhaltet und dann ein Sortierkriterium einbauen? Jeweils ein zusätzliches Sortierkriterium für die anderen Kolonnen würde auch nicht schaden.

    Vielleicht gäbe es sogar eine Möglichkeit, dass die unterschiedlichen Datumsbereiche farblich hervorgehoben werden. Könnte man über eine Abwechslung von Grau und Weiss erreichen.

    Grüssli



  • stimmt - groups wuerde sich aber auch anbieten


  • Administrator

    Mr Evil schrieb:

    stimmt - groups wuerde sich aber auch anbieten

    Hab mir schnell Groups angeschaut, ich glaube das wäre für Firefighter definitiv die beste Lösung. Geil was man damit anstellen kann 🙂

    Kann man eigentlich sowas auch über die WinAPI realisieren?

    Grüssli



  • Groups...hmmm das hört sich interessant an.Da werd ich mal ein Auge reinwerfen.Wenn ich fragen habe, weiß ich ja wo ich wieder fragen kann :p



  • Seh ich das richtig das man die "Groups" nicht mit XAML binden kann?Habe ausschließlich C# beispiele gefunden und das wollt ich eigentlich nicht unbedingt 🙂


  • Administrator

    Firefighter schrieb:

    Seh ich das richtig das man die "Groups" nicht mit XAML binden kann?Habe ausschließlich C# beispiele gefunden und das wollt ich eigentlich nicht unbedingt 🙂

    Geh mal in den Document Explorer, dort zur .Net Klassen Bibliothek, dann zu System.Windows.Controls, dann die Klasse ListView auswählen. Unter "More Code" gibt es ein "How to: Group Items in a ListView That Implements a GridView". Dieses Beispiel verwendet ausschliesslich XAML.

    Hier auch in der MSDN auf dem Netz:
    http://msdn.microsoft.com/en-us/library/ms754027.aspx

    Grüssli



  • Wie Peinlich, danke dir Dravere 🙂



  • genau
    wollte grad n beispiel raus suchen - hab bei mir in nem projekt auch schon listboxen gruppiert mit expandern (man kann dadurch die einzelnen gruppen auf und zu klappen



  • Könntest du das eventuell mal Posten?Wäre interessant zu wissen wie man das Professionell macht?


Anmelden zum Antworten