Question

i am using ObservableCollection to bind to the list box some strings: Here is my code for SongFinder:

     string title, downloadlink, artist, duration;
    private readonly HtmlWeb web = new HtmlWeb();
    public string Title
    {
        get { return title; }
        set { title = value; }
    }
    public string DownloadLink
    {
        get { return downloadlink; }
        set { downloadlink = value; }
    }
    public string Artist
    {
        get { return artist; }
        set { artist = value; }
    }
    public string Duration
    {
        get { return duration; }
        set { duration = value; }
    }

    public SongFinder(string pageuri)
    {

    }
    public void Mp3Monkey(string pageUri)
    {
        HtmlDocument doc = web.Load(pageUri);
        HtmlNode documentNode = doc.DocumentNode;
        doc.OptionUseIdAttribute = true;
        var xpath = "//div[@class='dd']/noindex/div";
        HtmlNodeCollection col = documentNode.SelectNodes(xpath);


        foreach (var n in col)
        {
            downloadlink = "https://www.mp3monkey.net/audio/" + n.SelectSingleNode("span[@id='oid']").InnerText + "/" + n.SelectSingleNode("span[@id='aid']").InnerText + "/" +
                        n.SelectSingleNode("span[@id='autor']").InnerText + "_-_" + n.SelectSingleNode("span[@id='title']").InnerText.Replace(" ", "_") + ".mp3";

            artist = n.SelectSingleNode("span[@id='autor']").InnerText;
            title = n.SelectSingleNode("span[@id='title']").InnerText;
            TimeSpan t = TimeSpan.FromSeconds(double.Parse(n.SelectSingleNode("span[@id='time']").InnerText));
            string answer = string.Format("{0:D2}:{1:D2}:{2:D2}",
             t.Hours,
             t.Minutes,
             t.Seconds);
            duration = answer;
        }
    }

Here is my code to bind the observable collection to the listbox:

    <ListBox x:Name="list" ItemsSource="{Binding}" HorizontalAlignment="Left" Height="365" Margin="73,187,0,0" VerticalAlignment="Top" Width="460">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel>
                    <TextBlock Text="{Binding Title}"/>
                    <TextBlock Text="{Binding Artist}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>

Here is my Code-Behind;

       this.DataContext = net;

        string Mp3Monkey1 = "Eminem Mp3 Download.htm";
        SongFinder find = new SongFinder(@"D:\books\" + Mp3Monkey1);
        find.Mp3Monkey(@"D:\books\" + Mp3Monkey1);
        net.Add(find);

Now the problem i am having is that when all the info is loaded the ListBox only displays the last song in the collection. Please Help!! And if i try to debug without binding it works fine and load all info for every song.

Why is that i want to know??

Any Help Would be appreciated

Was it helpful?

Solution

On your code you do overwrite your properties (Artist, Duration, etc ...) so obviously you will only see the last song that the foreach loop processed.

Solution:

Use a collection that you will fill in the loop by creating a new Song from each node in your HTMLNodeCollection

Example:

Code

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow
    {
        public MainWindow()
        {
            InitializeComponent();
            Loaded += MainWindow_Loaded;
        }

        private void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            // Let's pretend this is your HtmlNodeCollection 
            var collection = new List<Song>
            {
                new Song
                {
                    Artist = "Joeski & Chus",
                    Title = "El Amor",
                    Duration = TimeSpan.FromMinutes(5).TotalSeconds
                },
                new Song
                {
                    Artist = "Dano & Joeski",
                    Title = "For your love",
                    Duration = TimeSpan.FromMinutes(10).TotalSeconds
                },
            };

            // Build objects from your HTML nodes ...
            var songs = new ObservableCollection<Song>();
            foreach (Song song in collection)
            {
                songs.Add(song);
            }

            DataContext = songs;
        }
    }

    internal class Song
    {
        public string Artist { get; set; }
        public string Title { get; set; }
        public double Duration { get; set; }
    }
}

XAML

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:wpfApplication1="clr-namespace:WpfApplication1"
        Title="MainWindow"
        Width="525"
        Height="350">
    <Grid>
        <ListBox ItemsSource="{Binding}">
            <ListBox.ItemTemplate>
                <DataTemplate DataType="wpfApplication1:Song">
                    <Border Margin="2"
                            BorderBrush="Red"
                            BorderThickness="1">
                        <StackPanel>
                            <TextBlock Text="{Binding Artist, StringFormat='{}Artist: {0}'}" />
                            <TextBlock Text="{Binding Title, StringFormat='{}Title: {0}'}" />
                            <TextBlock Text="{Binding Duration, StringFormat='{}Duration: {0}'}" />
                        </StackPanel>
                    </Border>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>

Result

enter image description here

EDIT

Example with your code:

var songs = new ObservableCollection<Song>();
foreach (var n in col)
{
    Song song = new Song();
    downloadlink = "https://www.mp3monkey.net/audio/" + n.SelectSingleNode("span[@id='oid']").InnerText + "/" + n.SelectSingleNode("span[@id='aid']").InnerText + "/" +
                n.SelectSingleNode("span[@id='autor']").InnerText + "_-_" + n.SelectSingleNode("span[@id='title']").InnerText.Replace(" ", "_") + ".mp3";

    song.Artist = n.SelectSingleNode("span[@id='autor']").InnerText;
    song.Title = n.SelectSingleNode("span[@id='title']").InnerText;
    // etc ...

    songs.Add(song);    
}

DataContext = songs;

Make sure you do use my Song class and the ListBox along with the DataTemplate I've defined in XAML.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top