02/08/2013

[WindowsPhone] UserControl, TiltEffect, LiveTiles (Pin To Start)

Bonjour à toutes et à tous,
aujourd'hui on démarre avec les UserControl. On va voir comment les mettre en place et les personnaliser. Ensuite nous verrons des petites améliorations dans le cadre d'utilisation standard afin de mieux intégrer vos applications dans l'écosystème Windows Phone.

UserControl

Donc un UserControl est un contrôle personnalisable qui va posséder sa propre logique et que l'on va pouvoir réutiliser à chaque fois que cela sera nécessaire. (Dans un souci de factorisation de notre code).
Dans l'exemple prit tout au long de l'article nous allons réaliser un User Control qui affiche une Image et un Titre pour un article.
Donc nous allons commencer avec nos Dependency Properties.

Dependency Property

Les Dependency Properties sont un type de propriétés sur lesquelles reposent les piliers des technologies basées sur le XAML (j'entends ici bien évidemment les technologies WPF, Silverlight & Windows Phone). La puissance du XAML nous permet d'utiliser le styles, les animations et le Data Binding. C'est ensemble nécessite de calculer dynamiquement les valeurs de ces propriétés d'où l'importance des Dependency Properties.
Ici elles vont nous intéresser pour le Data Binding.

Donc nous démarrons par la création de notre User Control et des deux propriétés :

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 System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO.IsolatedStorage;
using System.Windows.Shapes;

namespace MyApp.View.UserControls
{
    public partial class MyPostUC : UserControl
    {
        public static DependencyProperty ImagePathProperty = DependencyProperty.Register("ImagePath", typeof(string), typeof(MyPostUC), new PropertyMetadata(null));
        public string ImagePath
        {
            get
            {
                return (string)GetValue(ImagePathProperty);
            }
            set
            {
                SetValue(ImagePathProperty, value);
            }

        }

        public static DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(MyPostUC), new PropertyMetadata(null));
        public string Title 
        {
            get
            {
                return (string)GetValue(TitleProperty);
                
            }
            set
            {
                SetValue(TitleProperty, value);
            }
        }

        public MyPostUC()
        {
            InitializeComponent();
        }
    }
}

Data Context

Une petite astuce pour notre Binding sur ces propriétés. Lorsque nous allons utiliser notre User Control le Data Context sera au niveau du contrôle et non au niveau du LayoutRoot, donc :

        public MyPostUC()
        {
            InitializeComponent();
            this.LayoutRoot.DataContext = this;
        }

TiltEffect

Tout d'abord, qu'est ce que le TiltEffect ?
Le TiltEffect est la légère distorsion qu'effectue certains contrôles lorsque ces derniers sont pressés avec le doigt.
Pour mettre cet effet en place nous allons télécharger le Windows Phone Toolkit avec NuGet (Pour rappel version 2.4 minimum pour du dev WP8).
Vous cliquez sur "Outils", "Gestionnaire de package de bibliothèque", "Console du Gestionnaire de package".
Install-Package WPtoolkit
Ensuite nous n'avons plus qu'à instancier côté XAML le Toolkit et à activer le TiltEffect.


LiveTile secondaire (Pin To Start)

Donc maintenant que nous avons notre User Control, qui va certainement alimenter le Data Template d'un LongListSelector, nous allons faire en sorte de créer un menu contextuel afin d'afficher un raccourci sur la Home
Tout d'abord, nous allons côté XAML créer ce menu contextuel (Ca tombe bien on a déjà installé le WPToolkit) :


    
        
            
        
    

Maintenant que nous avons le menu contextuel nous allons nous abonner à l'événement du click et réaliser notre tuile secondaire.
Donc pour expliquer le principe de la tuile secondaire ce type de tuile sont des tuiles qui affiche une ou plusieurs images. Nous allons dans un premier temps vérifier que notre tuile secondaire n'existe pas déjà. Ensuite nous créons une image à partir de l'image et du texte de notre contrôle que nous sauvegarderons dans l'Isolated Storage dans le Shared Content. Nous assignerons l'URI de la Tuile lors de sa création comme ceci :

        private void PinToHome_Click(object sender, RoutedEventArgs e)
        {
            var myItem = (sender as MenuItem).DataContext as PostItem;

            ShellTile TileToFind = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString().Contains(myItem.BloggerId));
            if (TileToFind == null)
            {
                var fontFamily = new FontFamily("Segoe WP SemiLight");
                var fontColor = new SolidColorBrush(Colors.White);
                var backgroundRectangle = new Rectangle() { Height = 173, Width = 173, Fill = (Brush)Application.Current.Resources["PhoneAccentBrush"] };

                string ttbTextligne1, ttbTextligne2;

                if (myItem.Title.Count() > 17)
                {
                    ttbTextligne1 = myItem.Title.Substring(0, myItem.Title.Substring(0, 17).Trim().LastIndexOf(" "));
                    ttbTextligne2 = myItem.Title.Substring(myItem.Title.Substring(0, 17).Trim().LastIndexOf(" ") + 1);
                    if (ttbTextligne2.Count() > 10)
                    {
                        ttbTextligne2 = ttbTextligne2.Substring(0, ttbTextligne2.Substring(0 , 10).LastIndexOf(" ")).Trim() + "...";
                    }
                }
                else
                {
                    ttbTextligne1 = myItem.Title;
                    ttbTextligne2 = "";
                }

                var textTextBlock = new TextBlock()
                {
                    Text = ttbTextligne1 + "\r\n" + ttbTextligne2,
                    FontSize = 20,
                    Width = 160,
                    TextWrapping = System.Windows.TextWrapping.Wrap,
                    FontWeight = FontWeights.Bold,
                    Foreground = fontColor,
                    FontFamily = fontFamily
                };

                var WBitmap = new WriteableBitmap(173, 173);
                WBitmap.Render(backgroundRectangle, new TranslateTransform());
                WBitmap.Render(textTextBlock, new TranslateTransform()
                {
                    X = 8,
                    Y = 105
                });

                WBitmap.Render(myImage, new TranslateTransform()
                {
                    X = 11,
                    Y = 11
                });

                WBitmap.Invalidate();

                using (IsolatedStorageFile store = IsolatedStorageFile.GetUserStoreForApplication())
                {
                    var stream = store.CreateFile("/Shared/ShellContent/" + myItem.Title.Replace("\"", "") + "tile.jpg");
                    WBitmap.SaveJpeg(stream, 173, 173, 0, 100);
                    stream.Close();
                }

                StandardTileData primaryTileData = new StandardTileData();
                primaryTileData.BackgroundImage = new Uri("isostore:/Shared/ShellContent/" + myItem.Title.Replace("\"", "") + "tile.jpg", UriKind.Absolute);
                Deployment.Current.Dispatcher.BeginInvoke(() =>
                    {
                        ShellTile.Create(new Uri("/View/BlogPostView.xaml?bid=" + myItem.BloggerId, UriKind.Relative), primaryTileData);
                    });
            }
        }

Je rajoute une dernière petite chose. Dans l'état actuel des choses, votre tuile secondaire sera créée ou pas en fonction de son existence mais quelque soit le cas le menu contextuel vous proposera toujours sa création. Pour y remédier, on s'abonne à l'événement du Loaded du MenuItem et l'on rajoute simplement :

        private void PinToHome_Loaded(object sender, RoutedEventArgs e)
        {
            var myItem = (sender as MenuItem).DataContext as PostItem;
            ShellTile TileToFind = ShellTile.ActiveTiles.FirstOrDefault(x => x.NavigationUri.ToString().Contains(myItem.BloggerId));
            if (TileToFind == null)
            {
                (sender as MenuItem).IsEnabled = true;
            }
            else
            {
                (sender as MenuItem).IsEnabled = false;
            }
        }

Conclusion

On a vu quelques notions sympas à creuser comme les Dependency Properties. Cela devrait, du moins je l'espère, vous permettre de rendre vos applications plus intuitives à vos utilisateurs Windows Phone.
C'est tout pour aujourd'hui.
On se retrouve lundi pour un nouveau tuto ou vendredi prochain pour un nouvel article.

Aucun commentaire:

Enregistrer un commentaire