WPF ListView, wie komme ich die daten aus dem Item?



  • Hallo,

    ich schreibe an einer kleinem WPF-Anwendung in der ich Bilder/Videos und Musik
    abspielen kann.Bei doppelklick auf das ListWiewItem, soll er den eingetragen
    Pfad auslesen und das lied abspielen.

    Hier der Code:

    Collection klasse

    [cpp]
        public class PictureCollection
        {
            public string Name
            {
                get;
                set;
            }
    
            public string Image
            {
                get;
                set;
            }
    
        }
    ///////////////window.xaml.cs//////////////////////////
    
            private ObservableCollection<PictureCollection> _PC =
            new ObservableCollection<PictureCollection>();
    
            public ObservableCollection<PictureCollection> PC
            {
                get { return _PC; }
            }
    
            void op_Closed(object sender, EventArgs e)
            {            
                System.Diagnostics.Debug.WriteLine(op.Path);
                this.path = op.Path;
                if (!string.IsNullOrEmpty(path))
                {
                    filelist = System.IO.Directory.GetFiles(path);
    
                    if (buttonname == "Bilder")
                    {
                        for (int i = 0; i < filelist.Length; i++)
                        {
                            _PC.Add(new PictureCollection() { Name = @filelist[i], Image = filelist[i] });
                        }
                    }
                    if (buttonname == "Musik")
                    {
                        for (int i = 0; i < filelist.Length; i++)
                        {
                            _PC.Add(new PictureCollection() { Name = @filelist[i], Image = filelist[i] });
                        }
                    }
                }        
            }
            int index = 0;
            private void listView1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
            {
    
                index = listView1.SelectedIndex;
                System.Diagnostics.Debug.WriteLine(index);
                System.Diagnostics.Debug.WriteLine(listView1.GetValue(ListView.ItemsSourceProperty));
            }
    [/cpp]
    

    Ich möchte jetzt wieder an die daten aus der Picturecollection kommen.
    Ich habe breakpoints gesetzt und sehe die geählten Daten, aber wie komme ich da ran?

    Danke schonmal



  • Hol dir statt SelectedIndex das SelectedItem, das ist bereits das richtige Objekt.

    //Dazu
    Unabhängig davon, wenn du mit WPF Arbeitest, arbeite lieber mit Bindings statt direkt mit den Liste, das ist so MFC und Forms like, altbackenes zeug gehört nicht in WPF.
    In dem zusammenhang sei das MVVM pattern genannt.



  • mhhh? ich arbeite doch mit Bindings.
    Und selecteditem funktioniert nicht so einfach, da es in meiner Collection
    steckt.

    Debug Anzeige des indexes und des selecteditems

    4
    MediaPlayer.PictureCollection
    

    Nun möchte ich aber etwas rausbekommen wie c:\\musik\Datei.mp3.

    Die bindings sind in der xaml

    <Window x:Class="MediaPlayer.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Name="myWindow1" Height="254" Width="522">
        <Grid>
            <StackPanel Width="120" Orientation="Vertical" HorizontalAlignment="Left" Background="CornflowerBlue">
                <Button x:Name="Bilder" Width="100" Height="35" Margin="0,10,0,0" Click="Button_Click">Bilder</Button>
                <Button x:Name="Musik" Width="100" Height="35" Margin="0,5,0,0" Click="Button_Click">Musik</Button>
                <Button x:Name="Videos" Width="100" Height="35" Margin="0,5,0,0" Click="Button_Click">Videos</Button> 
            </StackPanel>
            <ListView Margin="116,0,0,0" Name="listView1" ItemsSource="{Binding ElementName=myWindow1, Path=PC }" MouseDoubleClick="listView1_MouseDoubleClick">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>                    
                        <GridViewColumn Header="Picture" Width="100">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <Grid>
                                    <Image Source="{Binding Image}"/>
                                </Grid>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Description" Width="100" />
                    </GridView>
                </ListView.View>
            </ListView>
        </Grid>
    </Window>
    


  • Das "MediaPlayer.PictureCollection" ist doch dein Objekt, frag das doch nach dem Namen.
    (Du verwendest das wort Collection in PictureCollection obwohl es keine Collection ist, das verwirrt sehr)

    Es ist so
    man erstellt ein Objekt, nennen wir das Picture, dies bekommt die beiden Properties

    public class Picture
    {
        public string Name { get; set; }
        public string Image { get; set; }
    }
    

    Das wird dann zu einer Liste hinzu gefügt

    public ObservableCollection<Picture> Pictures { get; set; }
    

    Die Liste bindet dagegen:

    <ListView ItemsSource="{Binding Pictures}">
        <ListView.View>
            <GridView>
                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>                    
                <GridViewColumn Header="Picture" Width="100">
                    <GridViewColumn.CellTemplate>
                        <DataTemplate>
                            <Image Source="{Binding Image}"/>
                        </DataTemplate>
                    </GridViewColumn.CellTemplate>
                </GridViewColumn>
                <GridViewColumn Header="Description" Width="100" />
            </GridView>
        </ListView.View>
    </ListView>
    

    Dann hast du nun verschiedene möglichkeiten bei einem Doppelklick das objekt zu bekommen.

    Du erstellt noch ein "SelectedPicture" objekt und bindest dagegen

    public ObservableCollection<Picture> Pictures { get; set; }
    public Picture SelectedPicture { get; set; }
    
    <ListView ItemsSource="{Binding Pictures }" IsSynchronizedWithCurrentItem="True" SelectedItem="{Binding SelectedPicture}">
    

    In der OnClick methode Arbeitest du dann mit dem SelectedPicture

    private void listView1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        string name = SelectedPicture.Name;
    }
    

    Du holst dir das Selectierte objekt aus der ICollectionView

    <ListView ItemsSource="{Binding Pictures }" IsSynchronizedWithCurrentItem="True">
    
    private void listView1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
    {
        var collectionView = CollectionViewSource.GetDefaultView(Pictures);
        string name = collectionView.CurrentItem.Name;
    }
    

    Du kannst im übrigen

    DataContext = this;
    

    nach dem InitializeComponent hinzu fügen, dann brauchst du das ElementName in den Bindings nicht mehr.

    Eine anmerkung sei mir aber noch erlaubt.
    Dein Xaml code gefällt mir nicht.
    Du hast leider zu viele feste varianten.
    Die Buttons haben eine feste höhe oder breite, dein StackPanel hat eine feste weite usw
    sobald sich was am Text ändert musst du alles umstellen, WPF kann sich selber nach dem Inhalt anpassen, gib ihn die Chance.
    Zudem richtest du die Elemente mit den Margins aus, dafür sind diese nicht da.

    Erlaube mir bitte die Freiheit das ich dir sagen wie deine xaml ausshen sollte:

    <Window x:Class="MediaPlayer.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="Window1"
            Height="254" MinHeight="200"
            Width="522" MinWidth="300">
        <DockPanel>
            <StackPanel DockPanel.Dock="Left">
                <Button Content="Bilder" Click="Button_Click" />
                <Button Content="Musiks" Click="Button_Click" />
                <Button Content="Videos" Click="Button_Click" />
            </StackPanel>
            <ListView ItemsSource="{Binding PC}" MouseDoubleClick="listView1_MouseDoubleClick">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}"/>                    
                        <GridViewColumn Header="Picture" Width="100">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <Image Source="{Binding Image}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Description" Width="100" />
                    </GridView>
                </ListView.View>
            </ListView>
        </DockPanel>
    </Window>
    

    Mit richtiger lokalisierung und Commanding währe es:

    <Window x:Class="MediaPlayer.Window1"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            Title="{DynamicResource General_ApplicationName}"
            Height="254" MinHeight="200"
            Width="522" MinWidth="300">
        <DockPanel>
            <StackPanel DockPanel.Dock="Left">
                <Button Content="{DynamicResource Actions_Pictures}" Command="{Binding ShowPicturesCommand}" />
                <Button Content="{DynamicResource Actions_Musics}" Command="{Binding ShowMusicsCommand}" />
                <Button Content="{DynamicResource Actions_Videos}" Command="{Binding ShowVideosCommand}" />
            </StackPanel>
            <ListView ItemsSource="{Binding PC}">
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="{DynamicResource General_Name}" DisplayMemberBinding="{Binding Name}"/>                    
                        <GridViewColumn Header="{DynamicResource General_Picture}" Width="100">
                        <GridViewColumn.CellTemplate>
                            <DataTemplate>
                                <Image Source="{Binding Image}"/>
                            </DataTemplate>
                        </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="{DynamicResource General_Description}" Width="100" />
                    </GridView>
                </ListView.View>
            </ListView>
        </DockPanel>
    </Window>
    

    Doppelklick ist beim Commanding per Default leider nicht dabei, dafür kann man aber Behaviors schreiben (Stichwort: AttachedBehaviors) oder meine Library verwenden:

    <ListView ItemsSource="{Binding PC}" Events:EventBinding.EventBindings="{Events:EventBinding Events=1:MouseLeftButtonDown, Commands=1:MouseDownCommand}">
    

    Und wenn du die Column Spalten automatisch an die Fenster breite anpassen lassen willst, nimm meine EnhancedListView

    <Controls:EnhancedListView ResizeColumnWidths="True"
                               RightColumnDistance="20">
        <Controls:EnhancedListView.View>
            <GridView>
                <Controls:EnhancedGridViewColumn />
                <Controls:EnhancedGridViewColumn />
                <Controls:EnhancedGridViewColumn />
            </GridView>
        </Controls:EnhancedListView.View>
    </Controls:EnhancedListView>
    

    Diese Liste hat auch ein Build-in ein und ausblenden der Columns feature sowie Sorting.



  • Hi,

    Danke für die Anregungen, ja der xaml code ist nicht so schick,
    normal mach ich das über Blend und setzte die margins auch immer auf null,
    da es sonst zu unschönen Ergebnissen führen kann, und die größen lass ich
    dann auch dynamisch. war hier nur ein schneller Test.

    Aber ich habe noch eine performence Frage.

    In der listView sind jetzt zb 300+ Einträge. Wenn ich den Scrollbalken
    benutze ruckelt es extrem, lässt sich das irgendwie unterbinden?
    Wird immer alles gezeichnet, oder Zeichnet er nur den sichtbaren Bereich?
    Ich würde mich interessieren woran dies liegt.

    Danke



  • adonis schrieb:

    Aber ich habe noch eine performence Frage.

    In der listView sind jetzt zb 300+ Einträge. Wenn ich den Scrollbalken
    benutze ruckelt es extrem, lässt sich das irgendwie unterbinden?

    Ja, dazu gibt es auch einiges im Internet zu finden. Beispielsweise hier und hier, wobei es noch weit mehr [und imho bessere] Beschreibung dazu gibt.


Anmelden zum Antworten