Wypełnienie listbox'a listą obiektów

0

Mam taki problem. Problem polega na tym że nie mogę wyświetlić listy aktualności z kanału rss w listboxie. Jeśli chodzi o treść wszystko dobrze się pobiera i wczytuje do listy ale nie chce się pojawić w listboxie. Problem leży chyba w kolejności wykonywanych działań. Bo pierw następuje przypisanie pustej listy do source listboxa a następnie potem lista się wypełnia.

 public class RSSModelView
    {
        public List<RSSModel> lstFeeds;

        public RSSModelView(string url)
        {
            WebClient myRSS = new WebClient();

            myRSS.DownloadStringCompleted += new DownloadStringCompletedEventHandler(myRSS_DownloadStringCompleted);

            //Read Async
            myRSS.DownloadStringAsync(new Uri(url));
        }

        void myRSS_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            //Check if the Network is available
            if (Microsoft.Phone.Net.NetworkInformation.DeviceNetworkInformation.IsNetworkAvailable)
            {
                lstFeeds = new List<RSSModel>();

                lstFeeds = (from rss in XElement.Parse(e.Result).Descendants("item")
                            select new RSSModel(

                                rss.Element("title").Value,
                                rss.Element("link").Value,
                                rss.Element("description").Value,
                                rss.Element("author").Value,
                                rss.Element("pubDate").Value

                            )
                ).ToList<RSSModel>();
            }
            else
            {
                MessageBox.Show("No network is available...");
            }
        }
    }
public partial class AktPage : PhoneApplicationPage
    {
        WebClient myRSS = new WebClient();
        RSSModelView aktualnosci;

        public AktPage()
        {
            aktualnosci = new RSSModelView(@"http://jakisadres.pl/aktualnosci?format=feed&type=rss");
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(AktPage_Loaded);
            
        }
        void AktPage_Loaded(object sender, RoutedEventArgs e)
        {
            lstRSS.ItemsSource = aktualnosci.lstFeeds;
        }

        private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (lstRSS.SelectedItems.Count != 0)
            {
                RSSModel obj = aktualnosci.lstFeeds[lstRSS.SelectedIndex];
                NavigationService.Navigate(new Uri("/DetailsView.xaml?title=" + obj.Title, UriKind.Relative));
            }
        }
    } 
1

Spróbuj zmienić List<> na ObservablleCollection<> - ta druga implementuje INotifyPropertyChanged, więc lepiej nadaje się do data bindingu, bo po zmianie danych (np. odczycie) dane się powinny pojawić automatycznie.

Alternatywnie, możesz też po prostu ustawiać ItemsSource, dopiero, gdy dane są już dostępne, ale to by było brzydkie pogwałcenie MVVM ;-)

Możesz też obejrzeć klasę System.ServiceModel.Syndication.SyndicationFeed (ona jest w zewnętrznej bibliotece dla Silverlight, ale działa w WP7/8), która automatycznie parsuje RSS i Atom, zamiast użycia własnego XElement.

Polecam też przejść na WP8 ;-)

0

Zmieniłem na observable ale nie wiem jak zaimplementować INotifyPropertyChanged.

 public class RSSModelView
    {
        public ObservableCollection<RSSModel> lstFeeds;

        public RSSModelView(string url)
        {
            WebClient myRSS = new WebClient();

            myRSS.DownloadStringCompleted += new DownloadStringCompletedEventHandler(myRSS_DownloadStringCompleted);

            //Read Async
            myRSS.DownloadStringAsync(new Uri(url));
        }

        void myRSS_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
        {
            //Check if the Network is available
            if (Microsoft.Phone.Net.NetworkInformation.DeviceNetworkInformation.IsNetworkAvailable)
            {
                lstFeeds = new ObservableCollection<RSSModel>();

                lstFeeds = (from rss in XElement.Parse(e.Result).Descendants("item")
                            select new RSSModel(

                                rss.Element("title").Value,
                                rss.Element("link").Value,
                                rss.Element("description").Value,
                                rss.Element("author").Value,
                                rss.Element("pubDate").Value

                            )
                ).ToObservable<RSSModel>();
            }
            else
            {
                MessageBox.Show("No network is available...");
            }
        }
    }
public partial class AktPage : PhoneApplicationPage
    {
        WebClient myRSS = new WebClient();
        RSSModelView aktualnosci;

        public AktPage()
        {
            aktualnosci = new RSSModelView(@"http://jakisadres.pl/aktualnosci?format=feed&type=rss");
            InitializeComponent();
            this.Loaded += new RoutedEventHandler(AktPage_Loaded);
            
        }
        void AktPage_Loaded(object sender, RoutedEventArgs e)
        {
            lstRSS.ItemsSource = aktualnosci.lstFeeds;
        }

        private void ListBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            if (lstRSS.SelectedItems.Count != 0)
            {
                RSSModel obj = aktualnosci.lstFeeds[lstRSS.SelectedIndex];
                NavigationService.Navigate(new Uri("/DetailsView.xaml?title=" + obj.Title, UriKind.Relative));
            }
        }
    } 
1

Problem polega na tym, że ObservableCollection nie poinformuje swojego "słuchacza", że się całe zmieniło. Nawet przy ręcznej implementacji INotifyPropertyChanged okazuje się jednak, że po przypisaniu ItemsSource po prostu nie ma obiektu, który by nasłuchiwał zdarzenia PropertyChanged. Najłatwiej będzie pójść w drugą stronę - podpiąć się do kolekcji, ale dodawać do niej elementy po kolei, zamiast tworzyć nową.

Ja to zrobiłem w następujący sposób:

public partial class MainPage : PhoneApplicationPage
{

    WebClient myRSS = new WebClient();
    RSSModelView aktualnosci;

    // Constructor
    public MainPage()
    {

        aktualnosci = new RSSModelView(@"http://wiadomosci.wp.pl/kat,1329,ver,rss,rss.xml");
        InitializeComponent();
        lstRSS.ItemsSource = aktualnosci.lstFeeds;        
    }
}

oraz:

public class RSSModelView: INotifyPropertyChanged
{
    private ObservableCollection<RSSModel> _lstFeeds;
    public ObservableCollection<RSSModel> lstFeeds
    {
        get { return _lstFeeds; }
        set
        {
            if (_lstFeeds != value)
            {
                _lstFeeds = value;
                OnPropertyChanged("lstFeeds");
            }
        }
    }
        

    public RSSModelView(string url)
    {
        WebClient myRSS = new WebClient();
        this.lstFeeds = new ObservableCollection<RSSModel>();

        myRSS.DownloadStringCompleted += new DownloadStringCompletedEventHandler(myRSS_DownloadStringCompleted);
            
        myRSS.DownloadStringAsync(new Uri(url));            
    }

    void myRSS_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
    {
        //Check if the Network is available
        if (DeviceNetworkInformation.IsNetworkAvailable)
        {
            foreach (var item in from rss in XElement.Parse(e.Result).Descendants("item")
                select new RSSModel() {Title = rss.Element("title").Value})
            {
                lstFeeds.Add(item);                    
            }
        }
        else
        {
            MessageBox.Show("No network is available...");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string name)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(name));
    }
        
}

Trochę brzydki jest ten foreach, możesz nad nim pokombinować, aby był inny (plus ja użyłem inicjalizatora obiektu, a nie konstruktura).

1 użytkowników online, w tym zalogowanych: 0, gości: 1