29/07/2013

[WindowsPhone] Lecteur de flux : Couche View

Bonjour à toutes et à tous,
On se retrouve pour la troisième partie de la création de notre lecteur de flux RSS avec la création de la couche View.

Dossier complet

  1. [WindowsPhone] Lecteur de flux : Couche Model
  2. [WindowsPhone] Lecteur de flux : Couche ViewModel
  3. [WindowsPhone] Lecteur de flux : Couche View
  4. [WindowsPhone] Lecteur de flux : Le détail du post
  5. [WindowsPhone] Lecteur de flux : LiveTiles, Isolated Storage & BackgroundAgent

Mise en route

Bon, ça fait deux semaines qu'on est sur ce lecteur, ce serai pas mal qu'on puisse tester si ce qu'on a fait fonctionne. Donc on va faire le strict minimum pour vérifier visuellement qu'on récupère les données et les afficher. Donc c'est parti !
On démarre avec le MainPage.xaml.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Phone.Shell;
using SampleRSSReader.Resources;
using SampleRSSReader.ViewModel;
using SampleRSSReader.Model.POCO;

namespace SampleRSSReader
{
    public partial class MainPage : PhoneApplicationPage
    {

        ViewModelLocator vml;

        public MainPage()
        {
            InitializeComponent();
            vml = new ViewModelLocator();
            this.DataContext = vml;

        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            vml.OnNavigatedTo();
        }
    }
}

Donc on instancie notre ViewModelLocator et on définie le DataContext.
Enfin on va surcharger la méthode OnNavigatedTo et déclencher le chargement de nos ViewModel.
Maintenant, on va s'occuper d'un affichage minimaliste des ces données :

<phone:PhoneApplicationPage
    x:Class="SampleRSSReader.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">
    <!--LayoutRoot is the root grid where all page content is placed-->

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        <Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="MY APPLICATION" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="page name" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <phone:LongListSelector ItemsSource="{Binding PostsViewModel.MyBlogPosts}">
                <phone:LongListSelector.ItemTemplate>
                    <DataTemplate>
                        <TextBlock Text="{Binding Title}"/>
                    </DataTemplate>
                </phone:LongListSelector.ItemTemplate>
            </phone:LongListSelector>
        </Grid>
    </Grid>

</phone:PhoneApplicationPage>

Donc on rajoute un LongListSelector, on effectue notre Binding sur l'ObservableCollection de notre ViewModel. On édite l'ItemTemplate et on lui affecte un template avec un TextBlock qui se sera bindé sur la propriété Title.

On compile et on envoie ça sur notre émulateur.

Avec des Images c'est mieux !

Maintenant que tout fonctionne, on va "embellir" notre application en affichant des images.
Donc en fait les images sont contenues dans le contenu de l'article, il va donc falloir les isoler pour alimenter nos Image. Pour cela on va utiliser un Converter que j'ai déjà publié sur mon blog et que vous pouvez retrouver ici.

Donc on va ensuite déclarer notre Converter dans le fichier App.xaml :

<Application
    x:Class="SampleRSSReader.App"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"

    xmlns:conv="clr-namespace:SampleRSSReader.View.Converter">

    <!--Application Resources-->
    <Application.Resources>
        <local:LocalizedStrings xmlns:local="clr-namespace:SampleRSSReader" x:Key="LocalizedStrings"/>

        <conv:RSSImageConverter x:Key="ImagePicker" />

    </Application.Resources>

    <Application.ApplicationLifetimeObjects>
        <!--Required object that handles lifetime events for the application-->
        <shell:PhoneApplicationService
            Launching="Application_Launching" Closing="Application_Closing"
            Activated="Application_Activated" Deactivated="Application_Deactivated"/>
    </Application.ApplicationLifetimeObjects>

</Application>

Et enfin, on modifie notre DataTemplate sur MainPage.xaml :

<phone:PhoneApplicationPage
    x:Class="SampleRSSReader.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
    xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    FontFamily="{StaticResource PhoneFontFamilyNormal}"
    FontSize="{StaticResource PhoneFontSizeNormal}"
    Foreground="{StaticResource PhoneForegroundBrush}"
    SupportedOrientations="Portrait" Orientation="Portrait"
    shell:SystemTray.IsVisible="True">

    <!--LayoutRoot is the root grid where all page content is placed-->

    <Grid x:Name="LayoutRoot" Background="Transparent">
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>

        <!--TitlePanel contains the name of the application and page title-->
        <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
            <TextBlock Text="PASCALPEREZNET.BLOGSPOT.COM" Style="{StaticResource PhoneTextNormalStyle}" Margin="12,0"/>
            <TextBlock Text="Blog Posts" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
        </StackPanel>

        <!--ContentPanel - place additional content here-->
        <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
            <phone:LongListSelector ItemsSource="{Binding PostsViewModel.MyBlogPosts}">
                <phone:LongListSelector.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal" Margin="12">
                            <Image Source="{Binding Path=Content, Converter={StaticResource ImagePicker}}" Height="30" Width="30" Margin="0,0,12,0"/>
                            <TextBlock Text="{Binding Title}"/>
                        </StackPanel>
                    </DataTemplate>
                </phone:LongListSelector.ItemTemplate>
            </phone:LongListSelector>
        </Grid>
    </Grid>

</phone:PhoneApplicationPage>

On compile et on envoie au compilateur, je veux simplement attirer votre attention sur la valeur du Margin que j'ai utilisé dans mon StackPanel. C'est un 12, et ce n'est pas un 12 par hasard c'est que c'est le chiffre d'or à utiliser en Windows Phone pour la bonne et simple raison que c'est l'intervalle entre deux éléments pour arriver à sélectionner sur du tactile.

Accéder aux articles

Maintenant que nous avons notre liste, il serait intéressant de naviguer jusqu'à l'article. On va donc s'abonner au changement de sélection du LongListSelector pour récupérer l'url de l'article et utiliser le navigateur natif du téléphone :

MainPage.xaml
<phone:LongListSelector ItemsSource="{Binding PostsViewModel.MyBlogPosts}" SelectionChanged="LongListSelector_SelectionChanged">
                <phone:LongListSelector.ItemTemplate>
                    <DataTemplate>
                        <StackPanel Orientation="Horizontal" Margin="12">
                            <Image Source="{Binding Path=Content, Converter={StaticResource ImagePicker}}" Height="30" Width="30" Margin="0,0,10,0"/>
                            <TextBlock Text="{Binding Title}"/>
                        </StackPanel>
                    </DataTemplate>
                </phone:LongListSelector.ItemTemplate>
            </phone:LongListSelector>
MainPage.xaml.cs
        private void LongListSelector_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var myItem = (PostItem)(sender as LongListSelector).SelectedItem;
            WebBrowserTask myWebBrowser = new WebBrowserTask();
            myWebBrowser.Uri = new Uri(myItem.Link);
            myWebBrowser.Show();
        }

On compile et on envoie sur l'émulateur. On teste ça marche mais... Si vous vous choisi un élément qui se trouve à la fin de la liste, vous vous êtes rendu compte que vous êtes automatique rebasculé au le début de la liste.

La navigation

Le phénomène constaté plus haut est du au fait que lorsque nous avons effectué notre retour avec la touche back de notre téléphone pour revenir en arrière, la méthode OnNavigatedTo a été exécutée ce qui est logique puisque nous naviguions vers elle. Pour éviter d'avoir à nouveau ce phénomène :

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            if (e.NavigationMode != NavigationMode.Back)
            {
                base.OnNavigatedTo(e);
                vml.OnNavigatedTo();
            }
        }

Conclusion

Voilà ce sera le mot de la fin.
Comme d'habitude, vous pouvez retrouver les sources ici
La vidéo arrive dans les prochains jours !
A bientôt !

Aucun commentaire:

Enregistrer un commentaire