Windows Phone 7 - Tutoriel 23 : Doodle Pad

Logiciel de dessin simple avec InkPresenter en utilisant Silverlight sur Windows Phone 7

| Peter Bull | Deepin Prayag (Traduction) |

Traducteur

Deepin

Ce tutoriel fait partie d'une série de niveau débutant-intermédiaire pour apprendre Windows Phone 7 par le biais d'exemples pas à pas.

Langage : C#

Public visé : niveau Intermédiaire

Commentez ce tutoriel : Commentez ♪

- Titre : Windows Phone 7 - Tutoriel 23 : Doodle Pad

- Auteurs : Peter Bull, Deepin Prayag (Traduction)

- Traducteur : Deepin

- Parution : 23 mars 2012

- Mise à jour : 24 avril 2012

- Licence : Copyright ® 2012 Peter Bull. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- Traduction

- Introduction

- Logiciel de dessin simple avec InkPresenter en utilisant Silverlight sur Windows Phone 7

- Étape 1

- Étape 2

- Étape 3

- Étape 4

- Étape 5

- Étape 6

- Étape 7

- Étape 8

- Étape 9

- Étape 10

- Étape 11

- Étape 12

- Étape 13

- Étape 14

- Étape 15

- Étape 16

- Étape 17

- Étape 18

- Étape 19

- Étape 20

- Étape 21

- Étape 22

- Étape 23

- Étape 24

- Étape 25

- Étape 26

- Étape 27

- Étape 28

- Étape 29

- Conclusion

- Liens

- Remerciements

Traduction

Ce tutoriel est la traduction la plus fidèle possible du tutoriel original de Peter Bull, Windows Phone 7 - Simple Drawing Package with InkPresenter using Silverlight on Windows Phone 7.

Introduction

Doodle Pad est un logiciel de dessin simple utilisant le contrôle InkPresenter en Silverlight pour Windows Phone 7. L'application dispose des fonctionnalités pour définir la taille et la couleur, ainsi que la prise en charge des fonctions pour ouvrir/enregistrer en utilisant LINQ to XML.

Logiciel de dessin simple avec InkPresenter en utilisant Silverlight sur Windows Phone 7

Étape 1

Démarrez Microsoft Visual Web Developer 2010 Express pour Windows Phone, ensuite sélectionnez Fichier, puis Nouveau Projet… Sélectionnez Visual C#, ensuite Silverlight for Windows Phone, puis Application Windows Phone dans les modèles installés, sélectionnez un emplacement si vous le souhaitez, puis entrez un nom pour le projet et appuyez sur OK :

Étape 2

Une page Application Windows Phone nommée MainPage.xaml devrait alors apparaître :

Étape 3

Sélectionnez Projet, puis Ajouter une référence… La fenêtre Ajouter une référence devrait apparaître, sélectionnez System.Xml.Linq dans la liste .NET :

Étape 4

Ajoutez la référence à System.Xml.Linq en cliquant sur OK. Faites un clic droit sur l'entrée App.xaml dans l'Explorateur de solutions et choisissez Afficher le code. Dans la vue de code de App.xaml.cs, au-dessus de la ligne public App(), tapez ceci :

public string Filename { get; set;}
public object Content { get; set;}

Étape 5

Faites un clic droit sur le Projet dans l'Explorateur de solutions et choisissez Ajouter, ensuite Nouveau dossier et nommez-le « images » (sans les guillemets) :

Étape 6

Téléchargez les images suivantes (delete.png, new.png, open.png et save.png respectivement) en faisant un clic droit sur les images ci-dessous et en choisissant « Enregistrer l'image sous… ». Enregistrez-les dans un dossier sur votre ordinateur :

delete.png

new.png

open.png

save.png

Étape 7

Faites un clic droit sur le dossier « images » du Projet dans l'Explorateur de solutions, et choisissez Ajouter, ensuite Élément existant… Puis dans la fenêtre Ajouter un élément existant, sélectionnez le dossier dans lequel vous avez enregistré les images, puis choisissez Ajouter pour ajouter les images delete.png, new.png, open.png et save.png au dossier « images » dans le projet :

Étape 8

Toujours dans l'Explorateur de solutions, cliquez sur l'image « delete.png ». Ensuite allez dans la boite Propriétés et modifiez Action de génération à Contenu, faites la même chose pour les images « new.png », « open.png » et « save.png » :

Étape 9

Dans l'Explorateur de solutions, sélectionnez l'entrée Doodle Pad dans la liste, en dessous de l'entrée Solution. Ensuite sélectionnez Projet, puis Ajouter un nouvel élément… et sélectionnez le modèle Page en mode portrait Windows Phone, ensuite modifiez le Nom en OpenPage.xaml :

Étape 10

Cliquez sur Ajouter pour ajouter une nouvelle Page en mode portrait Windows Phone au Projet. Ensuite, dans le volet XAML de OpenPage.xaml, au-dessus de la balise <Grid x:Name="LayoutRoot" Background="Transparent">, tapez le code ApplicationBar XAML suivant :

<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="False">
<shell:ApplicationBar.Buttons>
<shell:ApplicationBarIconButton Text="open" IconUri="/images/open.png" Click="Open_Click"/>
<shell:ApplicationBarIconButton Text="delete" IconUri="/images/delete.png" Click="Delete_Click"/>
</shell:ApplicationBar.Buttons>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

Étape 11

Toujours dans le volet XAML, entre les lignes <Grid x:Name="ContentGrid" Grid.Row="1"> et </Grid>, tapez le code XAML suivant :

<ListBox Margin="10" FontSize="{StaticResource PhoneFontSizeExtraLarge}" Name="Files"/>

XAML :

Design :

Étape 12

Faites un clic droit sur la page ou sur l'entrée de OpenPage.xaml dans l'Explorateur de solutions et choisissez l'option Afficher le code. Dans la vue de code, au-dessus de namespace DoodlePad, tapez ceci :

using System.IO.IsolatedStorage;
using System.Xml.Linq;
using System.Windows.Ink;

Également dans la vue de code, au-dessus de public OpenPage(), tapez la déclaration Application suivante :

public App app = (App)Application.Current;

Étape 13

Puisque nous en sommes à la vue de code de OpenPage.xaml.cs, dans le constructeur public OpenPage() en dessous de InitializeComponent();, tapez ceci :

ApplicationTitle.Text = "DOODLE PAD";
PageTitle.Text = "open";
Loaded += (object sender, RoutedEventArgs e) =>
{
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
foreach (string filename in storage.GetFileNames("*.ipr"))
{
Files.Items.Add(filename.ToLower());
}
}
};

Étape 14

Toujours dans la vue de code de OpenPage.xaml.cs, en dessous du « } » de la méthode public OpenPage(), tapez les gestionnaires d'événements suivants :

private void Open_Click(object sender, EventArgs e)
{
if (Files.SelectedItem != null)
{
app.Filename = (string)Files.SelectedItem;
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
XElement _xml;
Stroke _stroke = new Stroke();
StrokeCollection _strokes = new StrokeCollection();
DrawingAttributes _drawAttr = new DrawingAttributes();
IsolatedStorageFileStream location = new IsolatedStorageFileStream(app.Filename,
System.IO.FileMode.Open, storage);
System.IO.StreamReader file = new System.IO.StreamReader(location);
_xml = XElement.Parse(file.ReadToEnd());
foreach (XElement element in _xml.Elements("Stroke"))
{
foreach (XElement item in element.Elements("Stroke.DrawingAttributes")
.Elements("DrawingAttributes"))
{
_drawAttr = new DrawingAttributes
{
Color = Color.FromArgb(
byte.Parse(item.Attribute("Color").Value.Substring(1, 2),
System.Globalization.NumberStyles.HexNumber),
byte.Parse(item.Attribute("Color").Value.Substring(3, 2),
System.Globalization.NumberStyles.HexNumber),
byte.Parse(item.Attribute("Color").Value.Substring(5, 2),
System.Globalization.NumberStyles.HexNumber),
byte.Parse(item.Attribute("Color").Value.Substring(7, 2),
System.Globalization.NumberStyles.HexNumber)),
Width = double.Parse(item.Attribute("Width").Value),
Height = double.Parse(item.Attribute("Height").Value)
};
}
foreach (XElement item in element.Elements("Stroke.StylusPoints"))
{
_stroke = new Stroke();
_stroke.DrawingAttributes = _drawAttr;
foreach (XElement point in item.Elements("StylusPoint"))
{
_stroke.StylusPoints.Add(new StylusPoint
{
X = double.Parse(point.Attribute("X").Value),
Y = double.Parse(point.Attribute("Y").Value)
});
}
_strokes.Add(_stroke);
}
}
app.Content = _strokes;
file.Dispose();
location.Dispose();
}
NavigationService.GoBack();
}
}

private void Delete_Click(object sender, EventArgs e)
{
if (Files.SelectedItem != null)
{
string _selected = (string)Files.SelectedItem;
if (MessageBox.Show("Delete selected Item " + _selected + "?", "Doodle Pad",
MessageBoxButton.OKCancel) == MessageBoxResult.OK)
{
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
if (storage.FileExists(_selected))
{
storage.DeleteFile(_selected);
}
}
NavigationService.GoBack();
}
}
}

Étape 15

Sélectionnez Projet, puis Ajouter un nouvel élément… et sélectionnez le modèle Page en mode portrait Windows Phone, ensuite modifiez le Nom en SavePage.xaml :

Étape 16

Cliquez sur Ajouter pour ajouter une nouvelle Page en mode portrait Windows Phone au Projet. Ensuite dans le concepteur de vues pour SavePage.xaml, dans le volet XAML entre les lignes <Grid x:Name="ContentGrid" Grid.Row="1"> et </Grid>, tapez le code XAML suivant :

<StackPanel>
<TextBlock Text="Filename"/>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBox Grid.Column="0" Name="Filename">
<TextBox.InputScope>
<InputScope>
<InputScopeName NameValue="FileName"/>
</InputScope>
</TextBox.InputScope>
</TextBox>
<Button Grid.Column="1" Content="save" Click="Save_Click"/>
</Grid>
</StackPanel>

XAML :

Design :

Étape 17

Faites un clic droit sur la page ou sur l'entrée de SavePage.xaml dans l'Explorateur de solutions et choisissez l'option Afficher le code. Dans la vue de code, au-dessus de namespace DoodlePad, tapez ceci :

using System.IO.IsolatedStorage;
using System.Xml.Linq;
using System.Windows.Ink;

Également dans la vue de code, au-dessus de public SavePage(), tapez la déclaration Application suivante :

public App app = (App)Application.Current;

Étape 18

Puisque nous en sommes à la vue de code de SavePage.xaml.cs, dans le constructeur public SavePage() en dessous de InitializeComponent();, tapez ceci :

ApplicationTitle.Text = "DOODLE PAD";
PageTitle.Text = "save";
Loaded += (object sender, RoutedEventArgs e) =>
{
if (app.Filename == null || app.Filename == "")
{
Filename.Text = "untitled.ipr";
}
else
{
Filename.Text = app.Filename;
}
};

Étape 19

Toujours dans la vue de code de SavePage.xaml.cs, en dessous du « } » de la méthode public SavePage(), tapez les gestionnaires d'événements suivants :

private void Save_Click(object sender, RoutedEventArgs e)
{
if (Filename.Text != "")
{
try
{
app.Filename = Filename.Text.Trim().ToLower();
using (IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForApplication())
{
XDocument _doc = new XDocument();
StrokeCollection _strokes = new StrokeCollection();
_strokes = (StrokeCollection)app.Content;
XElement _strokecollection = new XElement("StrokeCollection");
foreach (Stroke item in _strokes)
{
XElement _stroke = new XElement("Stroke");
XElement _strokeAttr = new XElement("Stroke.DrawingAttributes");
XElement _attributes = new XElement("DrawingAttributes");
XAttribute _color = new XAttribute("Color", item.DrawingAttributes.Color);
XAttribute _width = new XAttribute("Width", item.DrawingAttributes.Width);
XAttribute _height = new XAttribute("Height", item.DrawingAttributes.Height);
_attributes.Add(_color, _width, _height);
_strokeAttr.Add(_attributes);
XElement _points = new XElement("Stroke.StylusPoints");
foreach (StylusPoint point in item.StylusPoints)
{
XElement _point = new XElement("StylusPoint");
XAttribute _x = new XAttribute("X", point.X);
XAttribute _y = new XAttribute("Y", point.Y);
_point.Add(_x, _y);
_points.Add(_point);
}
_stroke.Add(_strokeAttr, _points);
_strokecollection.Add(_stroke);
}
_doc = new XDocument(new XDeclaration("1.0", "utf-8", "yes"), _strokecollection);
IsolatedStorageFileStream location = new IsolatedStorageFileStream(app.Filename,
System.IO.FileMode.Create, storage);
System.IO.StreamWriter file = new System.IO.StreamWriter(location);
_doc.Save(file);
app.Content = null;
file.Dispose();
location.Dispose();
}
NavigationService.GoBack();
}
catch
{
// Ignore Errors
}
}
}

Étape 20

Sélectionnez l'onglet MainPage.xaml, ensuite dans le volet XAML de MainPage.xaml, au-dessus de la balise <Grid x:Name="LayoutRoot" Background="Transparent">, tapez le code ApplicationBar XAML suivant :

<phone:PhoneApplicationPage.ApplicationBar>
<shell:ApplicationBar IsVisible="True" IsMenuEnabled="False">
<shell:ApplicationBar.Buttons>
<shell:ApplicationBarIconButton Text="new" IconUri="/images/new.png" Click="New_Click"/>
<shell:ApplicationBarIconButton Text="open" IconUri="/images/open.png" Click="Open_Click"/>
<shell:ApplicationBarIconButton Text="save" IconUri="/images/save.png" Click="Save_Click"/>
</shell:ApplicationBar.Buttons>
</shell:ApplicationBar>
</phone:PhoneApplicationPage.ApplicationBar>

Étape 21

Ensuite dans le volet XAML, entre les lignes <Grid x:Name="ContentGrid" Grid.Row="1"> et </Grid>, tapez le code XAML suivant :

<Grid x:Name="ContentMain">
<Grid.RowDefinitions>
<RowDefinition Height="90"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid x:Name="Toolbar" Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- Toolbar -->
</Grid>
<!-- Content -->
</Grid>

XAML :

Design :

Étape 22

Toujours dans le volet XAML au sein du Grid ContentMain, en dessous de <!--Toolbar-->, tapez le code ListBox XAML suivant :

<ListBox Grid.Column="0" Name="Size"
SelectionChanged="Size_SelectionChanged">
<ListBoxItem Tag="1">
<Rectangle Margin="10" Width="340" Height="1" Fill="{StaticResource PhoneAccentBrush}"/>
</ListBoxItem>
<ListBoxItem Tag="2">
<Rectangle Margin="10" Width="340" Height="2" Fill="{StaticResource PhoneAccentBrush}"/>
</ListBoxItem>
<ListBoxItem Tag="5" IsSelected="True">
<Rectangle Margin="10" Width="340" Height="5" Fill="{StaticResource PhoneAccentBrush}"/>
</ListBoxItem>
<ListBoxItem Tag="10">
<Rectangle Margin="10" Width="340" Height="10" Fill="{StaticResource PhoneAccentBrush}"/>
</ListBoxItem>
<ListBoxItem Tag="15">
<Rectangle Margin="10" Width="340" Height="15" Fill="{StaticResource PhoneAccentBrush}"/>
</ListBoxItem>
<ListBoxItem Tag="20">
<Rectangle Margin="10" Width="340" Height="20" Fill="{StaticResource PhoneAccentBrush}"/>
</ListBoxItem>
<ListBoxItem Tag="25">
<Rectangle Margin="10" Width="340" Height="25" Fill="{StaticResource PhoneAccentBrush}"/>
</ListBoxItem>
<ListBoxItem Tag="30">
<Rectangle Margin="10" Width="340" Height="30" Fill="{StaticResource PhoneAccentBrush}"/>
</ListBoxItem>
<ListBoxItem Tag="40">
<Rectangle Margin="10" Width="340" Height="40" Fill="{StaticResource PhoneAccentBrush}"/>
</ListBoxItem>
<ListBoxItem Tag="50">
<Rectangle Margin="10" Width="340" Height="50" Fill="{StaticResource PhoneAccentBrush}"/>
</ListBoxItem>
</ListBox>

<ListBox Grid.Column="1" Width="120" Name="Colour"
SelectionChanged="Colour_SelectionChanged">
<ListBoxItem Tag="FF000000" IsSelected="True">
<Rectangle Margin="5" Width="120" Height="20" Fill="Black"/>
</ListBoxItem>
<ListBoxItem Tag="FF808080">
<Rectangle Margin="5" Width="120" Height="20" Fill="Gray"/>
</ListBoxItem>
<ListBoxItem Tag="FFFF0000">
<Rectangle Margin="5" Width="120" Height="20" Fill="Red"/>
</ListBoxItem>
<ListBoxItem Tag="FFFFA500">
<Rectangle Margin="5" Width="120" Height="20" Fill="Orange"/>
</ListBoxItem>
<ListBoxItem Tag="FFFFFF00">
<Rectangle Margin="5" Width="120" Height="20" Fill="Yellow"/>
</ListBoxItem>
<ListBoxItem Tag="FF008000">
<Rectangle Margin="5" Width="120" Height="20" Fill="Green"/>
</ListBoxItem>
<ListBoxItem Tag="FF00FFFF">
<Rectangle Margin="5" Width="120" Height="20" Fill="Cyan"/>
</ListBoxItem>
<ListBoxItem Tag="FF0000FF">
<Rectangle Margin="5" Width="120" Height="20" Fill="Blue"/>
</ListBoxItem>
<ListBoxItem Tag="FFFF00FF">
<Rectangle Margin="5" Width="120" Height="20" Fill="Magenta"/>
</ListBoxItem>
<ListBoxItem Tag="FF800080">
<Rectangle Margin="5" Width="120" Height="20" Fill="Purple"/>
</ListBoxItem>
</ListBox>

XAML :

Design :

Étape 23

En étant toujours dans le volet XAML de MainPage.xaml, en dessous de la ligne <!-- Content -->, tapez le code InkPresenter XAML suivant :

<InkPresenter Grid.Row="1" Background="White" Name="Surface"
MouseLeftButtonDown="Surface_MouseLeftButtonDown"
MouseLeftButtonUp="Surface_MouseLeftButtonUp"
MouseMove="Surface_MouseMove" />

XAML :

Design :

Étape 24

Sélectionnez l'onglet MainPage.xaml, ensuite faites un clic droit sur la page ou sur l'entrée de MainPage.xaml dans l'Explorateur de solutions et choisissez l'option Afficher le code. Dans la vue de code, au-dessus de namespace DoodlePad, tapez ceci :

using System.Xml.Linq;
using System.Windows.Ink;

Également dans la vue de code, au-dessus de public MainPage(), tapez les déclarations suivantes :

public App app = (App)Application.Current;
public Stroke drawStroke;
public Color drawColour = Colors.Black;
public Size drawSize = new Size { Height = 5, Width = 5 };

Étape 25

Puisque nous en sommes à la vue de code de MainPage.xaml.cs, dans le constructeur public MainPage() en dessous de InitializeComponent();, tapez ceci :

ApplicationTitle.Text = "DOODLE PAD";
PageTitle.Text = "untitled.ipr";
Loaded += (object sender, RoutedEventArgs e) =>
{
if (app.Content != null)
{
Surface.Strokes.Clear();
Surface.Strokes = (StrokeCollection)app.Content;
}
if (app.Filename == null || app.Filename == "")
{
PageTitle.Text = "untitled.ipr";
}
else
{
PageTitle.Text = app.Filename;
}
};

Étape 26

En étant toujours dans la vue de code de MainPage.xaml.cs, en dessous du « } » de la méthode public MainPage(), tapez les gestionnaires d'événements suivants :

private void New_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Start a new Doodle?", "Doodle Pad",
MessageBoxButton.OKCancel) == MessageBoxResult.OK)
{
PageTitle.Text = "untitled.ipr";
Surface.Strokes.Clear();
app.Filename = PageTitle.Text;
app.Content = Surface.Strokes;
}
}

private void Open_Click(object sender, EventArgs e)
{
app.Content = Surface.Strokes;
NavigationService.Navigate(new Uri("/OpenPage.xaml", UriKind.Relative));
}

private void Save_Click(object sender, EventArgs e)
{
app.Content = Surface.Strokes;
NavigationService.Navigate(new Uri("/SavePage.xaml", UriKind.Relative));
}

private void Surface_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
drawStroke = new Stroke();
drawStroke.DrawingAttributes.Color = drawColour;
drawStroke.DrawingAttributes.Width = drawSize.Width;
drawStroke.DrawingAttributes.Height = drawSize.Height;
drawStroke.StylusPoints.Add(new StylusPoint
{
X = e.GetPosition(Surface).X,
Y= e.GetPosition(Surface).Y
});
Surface.Strokes.Add(drawStroke);
}

private void Surface_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
drawStroke = null;
}

private void Surface_MouseMove(object sender, MouseEventArgs e)
{
if (drawStroke != null)
{
drawStroke.StylusPoints.Add(new StylusPoint
{
X = e.GetPosition(Surface).X,
Y = e.GetPosition(Surface).Y
});
}
}

private void Size_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (Size != null)
{
double _drawWidth = double.Parse(((ListBoxItem)Size.SelectedItem).Tag.ToString());
drawSize = new Size { Height = _drawWidth, Width = _drawWidth };
}
}

private void Colour_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (Colour != null)
{
string _colour = (string)((ListBoxItem)Colour.SelectedItem).Tag;
drawColour = Color.FromArgb(
byte.Parse(_colour.Substring(0, 2),
System.Globalization.NumberStyles.HexNumber),
byte.Parse(_colour.Substring(2, 2),
System.Globalization.NumberStyles.HexNumber),
byte.Parse(_colour.Substring(4, 2),
System.Globalization.NumberStyles.HexNumber),
byte.Parse(_colour.Substring(6, 2),
System.Globalization.NumberStyles.HexNumber));
}
}

Étape 27

Enregistrez le Projet maintenant que vous avez terminé l'application Windows Phone Silverlight. Sélectionnez l'option Windows Phone Emulator, ensuite sélectionnez Debug puis Démarrer le débogage ou cliquez sur Démarrer le débogage :

Dès que vous l'aurez fait, ce qui suit apparaîtra dans l'émulateur Windows Phone une fois chargé :

Étape 28

Faites défiler la ListBox Colour puis appuyez sur une couleur, par exemple bleu pour sélectionner une couleur. Sélectionnez une taille de la même manière, puis appuyez et maintenez afin de dessiner quelque chose qui pourra ensuite être sauvegardé :

Étape 29

Vous pouvez ensuite Arrêter l'application en sélectionnant la fenêtre d'application Visual Studio 2010 et en cliquant sur le bouton Arrêter le débogage :

Conclusion

Ceci est un exemple simple d'application de dessin, utilisant InkPresenter et LINQ to XML pour enregistrer et ouvrir les « traits » utilisés pour dessiner. Essayez d'ajouter davantage de fonctionnalités telles que des tailles et des couleurs additionnelles - personnalisez-la !

Liens

Télécharger le code source du tutoriel.

Remerciements

Je tiens ici à remercier Peter Bull de m'avoir autorisé à traduire son tutoriel.
Je remercie tomlev pour sa relecture technique et ses propositions.
Je remercie également Gurdil_le_nain pour sa relecture orthographique et ses propositions.