Introduction

Absent de la version 2, le contrôle SaveFileDialog est enfin présent dans Silverlight 3. Celui-ci permet de sauvegarder du contenu en local et ouvre la voie à de nouveaux scénarios (téléchargement de fichiers depuis un serveur, génération de rapports puis sauvegarde en local, etc.).

Découvrons comment fonctionne ce nouveau contrôle.

L'application de démonstration est disponible en ligne ici.

I. Enregistrement de données dans un fichier

Nous allons partir d'une interface extrêmement simple contenant une TextBox et deux boutons.

Code XAML de l'application
Sélectionnez
<UserControl x:Class="SilverlightSaveFileDialogDemo.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Width="500" Height="300">
    <Canvas x:Name="LayoutRoot" Background="White">
<TextBox x:Name="txtArea" TextWrapping="Wrap" AcceptsReturn="True"/>
<Button Click="btnSave_Click" Content="Sauver le texte" />
<Button Click="btnSaveImage_Click" Content="Télécharger une image depuis le serveur"/>
<TextBlock x:Name="txtErrors" Foreground="Red"/>
<TextBlock Text="Entrez un texte :" TextWrapping="Wrap" />
</Canvas>
</UserControl>

Le premier bouton permettra de sauvegarder dans un fichier le texte saisi dans la TexBox. Un clic dessus appellera la méthode btnSave_Click qui va afficher la SaveFileDialog :

Sauvegarde du fichier texte
Sélectionnez
private void btnSave_Click(object sender, RoutedEventArgs e)
{
    SaveFileDialog saveDialog = new SaveFileDialog();
    saveDialog.DefaultExt = ".txt";
    saveDialog.Filter = "Fichiers texte (.txt)|*.txt|Tous les fichiers|*.*";
    saveDialog.FilterIndex = 1;

    bool? open = saveDialog.ShowDialog();
    if (open.HasValue && open.Value)
    {
        try
        {
            using (Stream fs = saveDialog.OpenFile())
            {
                byte[] info = (new UTF8Encoding(true)).GetBytes(txtArea.Text);
                fs.Write(info, 0, info.Length);
            }
        }
        catch (Exception ex)
        {
            txtErrors.Text = ex.Message;
        }
    }   
}

La propriété DefaultExt permet d'indiquer l'extension par défaut à ajouter au nom du fichier si l'utilisateur n'en saisit pas.

La propriété Filter spécifie les types de fichier et leur description pris en compte par la boite de dialogue.

La propriété FilterIndex indique l'index du filtre sélectionné par défaut. Attention, le premier filtre a un index égal à 1 et non à 0 !

La méthode ShowDialog affiche la fenêtre à l'écran. Un renvoie un Nullable<bool> qui vaut vrai si l'utilisateur clique sur le bouton « enregistrer » et faux s'il ferme ou clique sur le bouton « annuler » de la fenêtre.

La méthode OpenFile retourne un flux en écriture sur le fichier spécifié par l'utilisateur. Il nous est ainsi possible d'écrire dans le fichier via ce flux.


Voici le résultat en image :

savefile1.png


En appuyant sur le bouton « Sauver le texte » la boite de dialogue vous demandant de sélectionner un nom et un emplacement pour le fichier s'ouvre :

savefile2.png


Le fichier a bien été créé sur le bureau :

savefile3.png


En ouvrant le fichier nous pouvons vérifier que l'enregistrement s'est effectué correctement :

savefile4.png

II. Téléchargement d'un fichier

Un autre scénario maintenant possible est la possibilité de télécharger via l'application Silverlight un fichier se trouvant sur un serveur puis de le sauvegarder en local. Pour l'illustrer, nous allons télécharger une image puis l'enregistrer sur le poste de l'utilisateur.

La classe LoadFileRequest utilisée ici permet de télécharger un fichier donné. Une fois le téléchargement terminé l'évènement LoadFileRequestCompleted est levé.

 
Sélectionnez
private SaveFileDialog _saveImageDialog;
private void btnSaveImage_Click(object sender, RoutedEventArgs e)
{
    _saveImageDialog = new SaveFileDialog();
    _saveImageDialog.DefaultExt = ".jpg";
    _saveImageDialog.Filter = "Fichiers image (.jpg)|*.jpg|Tous les fichiers|*.*";
    _saveImageDialog.FilterIndex = 1;
    bool? open = _saveImageDialog.ShowDialog();
    if (open.HasValue && open.Value)
    {
        LoadFileRequest loadFileRequest = new LoadFileRequest(Config.URL_REP_IMAGES + "/Creek.jpg");
        loadFileRequest.LoadFileRequestCompleted += LoadFileRequestLoadFileRequestCompleted;
        loadFileRequest.Execute();
    }
}

Vous remarquerez que nous créons et affichons la SaveFileDialog avant de télécharger le fichier. Peut-être voudriez-vous d'abord télécharger le fichier puis afficher la boite de dialogue dans la fonction de callback LoadFileRequestLoadFileRequestCompleted. Cela n'est cependant pas possible dans notre exemple car le SaveFileDialog doit obligatoirement être créé suite à une action utilisateur (event handler suite au clic d'un bouton par exemple). La créer ailleurs, provoquerait la levée d'une exception.


Une fois le téléchargement terminé nous vérifions que nous avons bien récupéré le fichier puis l'enregistrons via le Stream créé par le SaveFileDialog.

 
Sélectionnez
void LoadFileRequestLoadImageRequestCompleted(object sender, LoadImageRequestCompletedEventArgs e)
{
    if (e.Result == null)
    {
        txtErrors.Text = "Pas de réponse de la requête !";
    }
    else
    {
        try
        {
            using (Stream fs = _saveImageDialog.OpenFile())
            {
                int length = Convert.ToInt32(e.Result.Length);
                byte[] byteResult = new byte[length];

                e.Result.Read(byteResult, 0, length);

                fs.Write(byteResult, 0, byteResult.Length);
            }
        }
        catch (Exception ex)
        {
            txtErrors.Text = ex.Message;
        }
    }
}

Encore une fois, n'oubliez un try/catch afin de pallier une erreur survenant lors de la sauvegarde.

Sources

Téléchargez les sources de la solution donnée en exemple.

Liens

Remerciements

J'adresse ici tous mes remerciements à l'équipe de rédaction de "developpez.com" pour le temps qu'ils ont bien voulu passer à la correction et à l'amélioration de cet article.

Contact

Si vous constatez une erreur dans le tutorial, dans les sources, dans la programmation ou pour toutes informations, n'hésitez pas à me contacter par le forum.