none
Flux rss-problem RRS feed

  • Question

  • Bonjour à tous,

    je veux faire la mise à jour de mon app qui lit des flux rss. au fait je veux ajouter le support de lecture d'actualités en mode offline.

    Donc j'ai choisi d'enregistrer l'actualité dans ma bd sql ce.

    voici le code que je prend pour charger les données provenant des flux rss

                                                           

    #region CHARGEUR D'INFORMATIONS AVEC OBSERVABLE COLLECTION
            public ObservableCollection<RssFeed> LoadingRssFeed2(string o)
            {

                ObservableCollection<RssFeed> me = new ObservableCollection<RssFeed>();
                HttpWebRequest web = HttpWebRequest.CreateHttp(o);
                web.AllowReadStreamBuffering = true;
                web.BeginGetResponse(result =>
                {
                    WebResponse response = web.EndGetResponse(result);
                    XDocument doc = XDocument.Load(response.GetResponseStream());
                    response.Close();

                    Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {


                        foreach (var evt in doc.Descendants("item"))
                        {


                            me.Add(new RssFeed
                            {
                                TitleName = evt.Element("title").Value,
                                Description = evt.Element("description").Value,
                                Pubdate = evt.Element("pubDate").Value,
                                Link = evt.Element("link").Value,
                                ImageUrl = evt.Element("Image").Value
                            });



                        }


                    });
                }, null);

                return me;
            }



            #endregion de plus au niveau du chargement de ma page voici le code que j'utilise

                   

    using System.Net;
    using System.Windows;
    using Microsoft.Phone.Controls;
    using System.IO;
    using System.Xml;
    using System.ServiceModel.Syndication;
    using System.Windows.Controls;
    using System;
    using Microsoft.Phone.Tasks;
    using System.Linq;
    using System.Collections.Generic;
    using gouv.ci.Model;
    using System.Windows.Media.Imaging;
    using JeffWilcox.Controls;
    using Microsoft.Phone.Shell;
    using System.Threading;
    using gouv.ci.ViewModel;

    namespace gouv.ci
    {
        public partial class MainPage : PhoneApplicationPage
        {


            public MainPage()
            {

                InitializeComponent();

                Loaded += new RoutedEventHandler(MainPage_Loaded);

            }


            void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                App.MainViewModel.Initialize();
                this.LayoutRoot.DataContext = App.MainViewModel;
                //Je veux sauvegarder les flux rss de la categories economie dans ma base de données
                App.MainViewModel.AddToDb(App.MainViewModel.Economie);

            }

            private void infos_Click(object sender, EventArgs e)
            {
                var fom = Application.Current.RootVisual as PhoneApplicationFrame;
                fom.Navigate(new Uri("/Page/infos.xaml", UriKind.RelativeOrAbsolute));

            }

            private void source_Click(object sender, EventArgs e)
            {
                var frm = Application.Current.RootVisual as PhoneApplicationFrame;
                frm.Navigate(new Uri("/Page/SourcePage.xaml", UriKind.RelativeOrAbsolute));
            }






        }
    }

    et le problème est qu'au niveau du this.LayoutRoot.DataContext = App.MainViewModel; tout ce passe bien j'ai les infos sur mon UI et après   App.MainViewModel.AddToDb(App.MainViewModel.Economie);  ma base de données est vide. J'ai remarqué egalement que lorsque j'utilise intellitrace que je fait une execution pas à pas la methode que j'utilise pour charger les informations retourne toujours un objet null. Je suis un peu perdu.

    merci pour votre aide.


    windows phone 7

    lundi 11 mars 2013 11:20

Réponses

  • Le "return me" est correct, pas de soucis la dessus, sa observableCollection est bien initialisé auparavant et il l'a nourri juste après.

    Le problème en fait est autre : tu ne fais pas le

                App.MainViewModel.AddToDb(App.MainViewModel.Economie);

    au bon endroit car à ce moment là, tu n'es pas forcément encore passé dans la callback de ta requête.

    Même si l'observableCollection est juste, perso, je privilégierais une List<> car tu ne fais pas d'opération dessus.

    Ton code devient donc :

    #region CHARGEUR D'INFORMATIONS AVEC OBSERVABLE COLLECTION
    
    public List<RSSFeed> Economie{get;set;}
    
            public void LoadingRssFeed2(string o)
            {
    
                
                HttpWebRequest web = HttpWebRequest.CreateHttp(o);
                web.AllowReadStreamBuffering = true;
                web.BeginGetResponse(result =>
                {
                    WebResponse response = web.EndGetResponse(result);
                    XDocument doc = XDocument.Load(response.GetResponseStream());
                    response.Close();
    
                    
    
    var me = new List<RssFeed>();
                        foreach (var evt in doc.Descendants("item"))
                        {
    
    
                            me.Add(new RssFeed
                            {
                                TitleName = evt.Element("title").Value,
                                Description = evt.Element("description").Value,
                                Pubdate = evt.Element("pubDate").Value,
                                Link = evt.Element("link").Value,
                                ImageUrl = evt.Element("Image").Value
                            });
    
    
    
                        }
    
    Economie=me;
      //Je veux sauvegarder les flux rss de la categories economie dans ma base de données
                
    AddToDb(Economie);
    
    
    Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
    RaisePropertyChanged("Feeds");
                    });
                }, null);
    
             
            }
    
    
            #endregion de plus au niveau du chargement de ma page voici le code que j'utilise
                   
    using System.Net;
    using System.Windows;
    using Microsoft.Phone.Controls;
    using System.IO;
    using System.Xml;
    using System.ServiceModel.Syndication;
    using System.Windows.Controls;
    using System;
    using Microsoft.Phone.Tasks;
    using System.Linq;
    using System.Collections.Generic;
    using gouv.ci.Model;
    using System.Windows.Media.Imaging;
    using JeffWilcox.Controls;
    using Microsoft.Phone.Shell;
    using System.Threading;
    using gouv.ci.ViewModel;
    
    namespace gouv.ci
    {
        public partial class MainPage : PhoneApplicationPage
        {
    
    
            public MainPage()
            {
    
                InitializeComponent();
    
                Loaded += new RoutedEventHandler(MainPage_Loaded);
    
            }
    
    
            void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                App.MainViewModel.Initialize();
                this.LayoutRoot.DataContext = App.MainViewModel;
              
    
            }
    
            private void infos_Click(object sender, EventArgs e)
            {
                var fom = Application.Current.RootVisual as PhoneApplicationFrame;
                fom.Navigate(new Uri("/Page/infos.xaml", UriKind.RelativeOrAbsolute));
    
            }
    
            private void source_Click(object sender, EventArgs e)
            {
                var frm = Application.Current.RootVisual as PhoneApplicationFrame;
                frm.Navigate(new Uri("/Page/SourcePage.xaml", UriKind.RelativeOrAbsolute));
            }
    
    
    
    
    
    
        }
    }

    J'ai remplacé par une List<>, j'ai déplacé le AddToDB dans la callback de ta requête et il te suffira de binder ta ListBox avec Economie

    <ListBox ItemsSource="{Binding Economie}" />

    Sinon RaisePropertyChanged ressemble à ça 

        public void RaisePropertyChanged(String name)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(name));
    
            }

    en faisant hériter ton VM de INotifyPropertyChanged

    Voilou


    S'il vous plaît n'oublier pas de marquer la ou les réponses qui aident à résoudre votre problème. Pour que la discussion puisse être marquée comme résolue

    • Marqué comme réponse phorekonan lundi 11 mars 2013 12:46
    lundi 11 mars 2013 12:41
    Modérateur

Toutes les réponses

  • merci Dorian

    windows phone 7

    lundi 11 mars 2013 12:12
  • Je vois potentiellement une erreur lors de la récupération du Flux.

    On passera dans le "return me" avant que le flux soit téléchargé ce qui explique le null.

    Je t'invite à utiliser un "ManualResetEvent" pour gérer le téléchargement, tu as un exemple sur mon blog :

    http://dorianlamande.wordpress.com/2012/10/31/portable-class-library/

    Pour l'observable collection, tu n'en as pas besoin. Utilise plutôt un IEnumerable<RssFeed>. 

    L'observable collection est utilisée dans le cas où tu agis directement sur ta liste (clear, add, remove, ...) et que celle-ci est bindée dans le XAML afin de bénificier de la puissance de ICollectionChanged. Dans ton cas, tu ne récupères que de l'info qui ne sera pas modifiée.

    Cordialement,


    Dorian LAMANDE



    lundi 11 mars 2013 12:15
  • Le "return me" est correct, pas de soucis la dessus, sa observableCollection est bien initialisé auparavant et il l'a nourri juste après.

    Le problème en fait est autre : tu ne fais pas le

                App.MainViewModel.AddToDb(App.MainViewModel.Economie);

    au bon endroit car à ce moment là, tu n'es pas forcément encore passé dans la callback de ta requête.

    Même si l'observableCollection est juste, perso, je privilégierais une List<> car tu ne fais pas d'opération dessus.

    Ton code devient donc :

    #region CHARGEUR D'INFORMATIONS AVEC OBSERVABLE COLLECTION
    
    public List<RSSFeed> Economie{get;set;}
    
            public void LoadingRssFeed2(string o)
            {
    
                
                HttpWebRequest web = HttpWebRequest.CreateHttp(o);
                web.AllowReadStreamBuffering = true;
                web.BeginGetResponse(result =>
                {
                    WebResponse response = web.EndGetResponse(result);
                    XDocument doc = XDocument.Load(response.GetResponseStream());
                    response.Close();
    
                    
    
    var me = new List<RssFeed>();
                        foreach (var evt in doc.Descendants("item"))
                        {
    
    
                            me.Add(new RssFeed
                            {
                                TitleName = evt.Element("title").Value,
                                Description = evt.Element("description").Value,
                                Pubdate = evt.Element("pubDate").Value,
                                Link = evt.Element("link").Value,
                                ImageUrl = evt.Element("Image").Value
                            });
    
    
    
                        }
    
    Economie=me;
      //Je veux sauvegarder les flux rss de la categories economie dans ma base de données
                
    AddToDb(Economie);
    
    
    Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
    RaisePropertyChanged("Feeds");
                    });
                }, null);
    
             
            }
    
    
            #endregion de plus au niveau du chargement de ma page voici le code que j'utilise
                   
    using System.Net;
    using System.Windows;
    using Microsoft.Phone.Controls;
    using System.IO;
    using System.Xml;
    using System.ServiceModel.Syndication;
    using System.Windows.Controls;
    using System;
    using Microsoft.Phone.Tasks;
    using System.Linq;
    using System.Collections.Generic;
    using gouv.ci.Model;
    using System.Windows.Media.Imaging;
    using JeffWilcox.Controls;
    using Microsoft.Phone.Shell;
    using System.Threading;
    using gouv.ci.ViewModel;
    
    namespace gouv.ci
    {
        public partial class MainPage : PhoneApplicationPage
        {
    
    
            public MainPage()
            {
    
                InitializeComponent();
    
                Loaded += new RoutedEventHandler(MainPage_Loaded);
    
            }
    
    
            void MainPage_Loaded(object sender, RoutedEventArgs e)
            {
                App.MainViewModel.Initialize();
                this.LayoutRoot.DataContext = App.MainViewModel;
              
    
            }
    
            private void infos_Click(object sender, EventArgs e)
            {
                var fom = Application.Current.RootVisual as PhoneApplicationFrame;
                fom.Navigate(new Uri("/Page/infos.xaml", UriKind.RelativeOrAbsolute));
    
            }
    
            private void source_Click(object sender, EventArgs e)
            {
                var frm = Application.Current.RootVisual as PhoneApplicationFrame;
                frm.Navigate(new Uri("/Page/SourcePage.xaml", UriKind.RelativeOrAbsolute));
            }
    
    
    
    
    
    
        }
    }

    J'ai remplacé par une List<>, j'ai déplacé le AddToDB dans la callback de ta requête et il te suffira de binder ta ListBox avec Economie

    <ListBox ItemsSource="{Binding Economie}" />

    Sinon RaisePropertyChanged ressemble à ça 

        public void RaisePropertyChanged(String name)
            {
                if (PropertyChanged != null)
                    PropertyChanged(this, new PropertyChangedEventArgs(name));
    
            }

    en faisant hériter ton VM de INotifyPropertyChanged

    Voilou


    S'il vous plaît n'oublier pas de marquer la ou les réponses qui aident à résoudre votre problème. Pour que la discussion puisse être marquée comme résolue

    • Marqué comme réponse phorekonan lundi 11 mars 2013 12:46
    lundi 11 mars 2013 12:41
    Modérateur
  • C'est moche d'appeler le RaisePropertyChanged depuis une couche qui se doit d'être une couche de service.

    L'application semble avoir un problème de pattern...

    Pas convaincu non plus par l'usage d'une liste, pourquoi ne pas utiliser simplement une IEnumerable ?

    Dommage...


    Dorian LAMANDE

    lundi 11 mars 2013 13:07
  • tout simplement car une IEnumerable ça ne s'instancie pas... Et pour info, une List est une IEnumerable !

    Après pour le RaisePropertyChanged, il se trouve que c'est son VM ici, donc aucun soucis , il pourra par la suite extraire tout cela s'il le souhaite pour faire un M V VM Service, ce qui n'est pas encore son cas

    Enfin permet moi d'indiquer que le ManuelResetEvent est clairement pas top : pas fan de bloquer un thread et gros problème d'appel concurrent et pour finir, tu n'as pas géré le problème de pas de connexion. Il vaut mieux que ta portable library soit totalement asynchrone ou retourne des Tasks et que dans ton client (W8/WP8) tu lui rajoutes une couche pour gérer async...await.


    S'il vous plaît n'oublier pas de marquer la ou les réponses qui aident à résoudre votre problème. Pour que la discussion puisse être marquée comme résolue




    mardi 12 mars 2013 09:30
    Modérateur
  • Je prends note Rudy :)

    async / await pas dispo sur WP7 (même si dans mon billet je ne parle que de WP8/W8).

    La gestion de la connexion, est faite avant d'être dans la portable library. 

    Pour le IEnumerable ok, je n'avais pas vu qu'il était dans son VM.  Je pensais qu'il ferait une méthode dans un service qui retournerait un IEnumerable qui serait ensuite bindée ...

    Si on veut aller plus loin, ajoutons "private set" dans ce cas sur la liste, à quoi bon pouvoir la setter ailleurs que dans le VM ?

    Et factorisons un peu le code aussi :

    var fom = Application.Current.RootVisual as PhoneApplicationFrame;
                fom.Navigate(new Uri("/Page/infos.xaml", UriKind.RelativeOrAbsolute));

    Copy/Paste Pattern !

    A+


    Dorian LAMANDE


    mardi 12 mars 2013 11:11