web-dev-qa-db-fra.com

Silverlight DataGrid: Exporter vers Excel ou csv

Existe-t-il un moyen d'exporter mes données Silverlight DataGrid vers Excel ou csv?

J'ai cherché sur le Web, mais je ne trouve aucun exemple!

Merci beaucoup 

22
DLL

Silverlight 3 modifie la réponse à cette question car il donne la possibilité à l'utilisateur de créer un fichier sur le bureau de l'utilisateur dans un emplacement spécifié. J'ai adapté le code soumis par DaniCE, scindé les choses en quelques méthodes de lisibilité et utilisé un format CSV mal défini que Excel devrait reconnaître.

private void exportHistoryButton_Click(object sender, RoutedEventArgs e) 
{
    string data = ExportDataGrid(true, historyDataGrid);
    SaveFileDialog sfd = new SaveFileDialog()
    {
    DefaultExt = "csv",
    Filter = "CSV Files (*.csv)|*.csv|All files (*.*)|*.*",
    FilterIndex = 1
    };
    if (sfd.ShowDialog() == true)
    {
    using (Stream stream = sfd.OpenFile())
    {
        using (StreamWriter writer = new StreamWriter(stream)) {
        writer.Write(data);
        writer.Close();
        }
        stream.Close();
    }
    }
}

private string FormatCSVField(string data) {
    return String.Format("\"{0}\"",
        data.Replace("\"", "\"\"\"")
        .Replace("\n", "")
        .Replace("\r", "")
        );
}

public string ExportDataGrid(bool withHeaders, DataGrid grid)
{
    string colPath;
    System.Reflection.PropertyInfo propInfo;
    System.Windows.Data.Binding binding;
    System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
    System.Collections.IList source = (grid.ItemsSource as System.Collections.IList);
    if (source == null)
    return "";

    List<string> headers = new List<string>();
    grid.Columns.ToList().ForEach(col => {
    if (col is DataGridBoundColumn){
        headers.Add(FormatCSVField(col.Header.ToString()));
    }
    });
    strBuilder
    .Append(String.Join(",", headers.ToArray()))
    .Append("\r\n");

    foreach (Object data in source)
    {
    List<string> csvRow = new List<string>();
    foreach (DataGridColumn col in grid.Columns)
    {
        if (col is DataGridBoundColumn)
        {
        binding = (col as DataGridBoundColumn).Binding;
        colPath = binding.Path.Path;
        propInfo = data.GetType().GetProperty(colPath);
        if (propInfo != null)
        {
            csvRow.Add(FormatCSVField(propInfo.GetValue(data, null).ToString()));
        }
        }
    }
    strBuilder
        .Append(String.Join(",", csvRow.ToArray()))
        .Append("\r\n");
    }


    return strBuilder.ToString();
}
21
t3rse

J'ai trouvé ceci en utilisant le presse-papier.

Pour rendre le code générique, vous pouvez modifier le premier exemple pour lire les liaisons de colonne et les appliquer aux données à l'aide de la réflexion:

public String ExportDataGrid(DataGrid grid)
{
    string colPath;
    System.Reflection.PropertyInfo propInfo;
    System.Windows.Data.Binding binding;
    System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
    System.Collections.IList source = (grid.DataContext as System.Collections.IList);
    if (source == null)
        return "";

    foreach (Object data in source)
    {
        foreach (DataGridColumn col in datagrid.Columns)
        {
            if (col is DataGridBoundColumn)
            {
                binding = (col as DataGridBoundColumn).Binding;
                colPath = binding.Path.Path;
                propInfo = data.GetType().GetProperty(colPath);
                if (propInfo != null)
                {
                    strBuilder.Append(propInfo.GetValue(data, null).ToString());
                    strBuilder.Append(",");
                }                        
            }

        }
        strBuilder.Append("\r\n");
    }


    return strBuilder.ToString();
}

bien entendu, cela ne fonctionne que lorsque le chemin de la liaison est le nom de la propriété. Pour des chemins plus avancés, vous devez appliquer la liaison aux données (je suppose que ce serait une meilleure solution, mais je ne suis pas sûr de savoir comment procéder).

4
DaniCE

Je sais que c'est un ancien post, mais il m'a aidé. J'ai apporté quelques modifications pour que cela fonctionne avec silverlight 4, convertis et Excel. Je voulais l’exportation rapide et j’ai d’abord utilisé le format CSV, puis l’ouvert avec Excel. Ce code fonctionne avec Silverlight Web et avec une confiance élevée. Dans Web ne sera pas ouvert dans Excel.

     private static void OpenExcelFile(string Path)
    {
        dynamic excelApp;
        excelApp = AutomationFactory.CreateObject("Excel.Application");
        dynamic workbook = excelApp.workbooks;
        object oMissing = Missing.Value;

        workbook = excelApp.Workbooks.Open(Path,

           oMissing, oMissing, oMissing, oMissing, oMissing,

           oMissing, oMissing, oMissing, oMissing, oMissing,

           oMissing, oMissing, oMissing, oMissing);



        dynamic sheet = excelApp.ActiveSheet;


        // open the existing sheet


        sheet.Cells.EntireColumn.AutoFit();
        excelApp.Visible = true;
    }
    private static string FormatCSVField(string data)
    {
        return String.Format("\"{0}\"",
            data.Replace("\"", "\"\"\"")
            .Replace("\n", "")
            .Replace("\r", "")
            );
    }
   public  static string ExportDataGrid(DataGrid grid,string SaveFileName,bool AutoOpen)
    {
        string colPath;
        System.Reflection.PropertyInfo propInfo;
        System.Windows.Data.Binding binding;
        System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
       var source = grid.ItemsSource;

        if (source == null)
            return "";

        List<string> headers = new List<string>();
        grid.Columns.ToList().ForEach(col =>
        {
            if (col is DataGridBoundColumn)
            {
                headers.Add(FormatCSVField(col.Header.ToString()));
            }
        });
        strBuilder
        .Append(String.Join(",", headers.ToArray()))
        .Append("\r\n");

        foreach (var data in source)
        {
                List<string> csvRow = new List<string>();
                foreach (DataGridColumn col in grid.Columns)
                {
                    if (col is DataGridBoundColumn)
                    {
                        binding = (col as DataGridBoundColumn).Binding;
                        colPath = binding.Path.Path;

                        propInfo = data.GetType().GetProperty(colPath);
                        if (propInfo != null)
                        {
                            string valueConverted = "";
                            if (binding.Converter.GetType().ToString() != "System.Windows.Controls.DataGridValueConverter")
                                valueConverted = binding.Converter.Convert(propInfo.GetValue(data, null), typeof(System.String), binding.ConverterParameter, System.Globalization.CultureInfo.CurrentCulture).ToString();
                            else
                                valueConverted = FormatCSVField(propInfo.GetValue(data, null) == null ? "" : propInfo.GetValue(data, null).ToString());

                            csvRow.Add(valueConverted.ToString());
                        }
                    }
                }
                strBuilder
                    .Append(String.Join(",", csvRow.ToArray()))
                    .Append("\r\n");
            }

        if (AutomationFactory.IsAvailable)
        {
            var sampleFile = "\\" + SaveFileName;
            var path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            path += "\\Pement";


            if (!System.IO.Directory.Exists(path))
            {
                System.IO.Directory.CreateDirectory(path);
            }
            else
            {
                var files = System.IO.Directory.EnumerateFiles(path);
                foreach (var item in files)
                {
                    try
                    {
                        System.IO.File.Delete(item);
                    }
                    catch { }
                }
            }

            StreamWriter sw = File.CreateText(path + sampleFile);
            sw.WriteLine(strBuilder.ToString());
            sw.Close();

            if (AutoOpen)
                OpenExcelFile(path + sampleFile, true, true);
        }
        else
        {
            SaveFileDialog sfd = new SaveFileDialog()
            {
                DefaultExt = "csv",
                Filter = "CSV Files (*.csv)|*.csv|All files (*.*)|*.*",
                FilterIndex = 1
            };
            if (sfd.ShowDialog() == true)
            {
                using (Stream stream = sfd.OpenFile())
                {
                    using (StreamWriter writer = new StreamWriter(stream))
                    {
                        writer.Write(strBuilder.ToString());
                        writer.Close();
                    }
                    stream.Close();
                }
            } 
        }
        return strBuilder.ToString();
    }
2
Andrew

Je ne pense pas que Silverlight offre un moyen de télécharger des fichiers. Vous pouvez ajouter un bouton à votre application qui appelle une URL, c'est-à-dire http://www.mysite.com/generateexcelfile.aspx . Incluez en tant que valeurs de chaîne de caractères les paramètres utilisés pour générer les données affichées dans votre application Silverlight, exécutez votre requête et utilisez votre composant de génération de fichier Excel préféré pour générer le fichier à la volée. Redirectionz-le et il sera téléchargé sur le système des utilisateurs.

2
Dave Swersky

De mémoire, je dirais que vous pouvez ajouter le bouton d'exportation à l'aide de ControlTemplate, puis parcourir chaque élément de la DataSource, puis utiliser chaque colonne de Columns pour obtenir le contenu de chaque cellule à l'aide de la méthode GetCellContent Informations de liaison de DataGridColumn pour obtenir la valeur de cellule appropriée. Vous pouvez ensuite obtenir la valeur affichée de ce contenu et l'écrire dans votre rapport. 

Quelque chose comme...

foreach (YourType item in grid.DataSource)
{
   foreach (DataGridColumn column in grid.Columns)
   {
      FrameworkElement cellContent = column.GetCellContent(item);

      // Now, determine the type of cell content and act accordingly.
      TextBlock block = cellContent as TextBlock;
      if (block != null)
      {
         // Report text value...
      }

      // ...etc...

   }
}

Ou en utilisant les informations de liaison comme décrit par DaniCE .

1
Jeff Yates

Vérifiez la solution de Ryan. Ça a l'air bien, je ne peux pas en témoigner parce que je viens de le trouver. Ryan fait ce que DLL ci-dessus a demandé.

http://www.rshelby.com/post/exporting-data-from-silverilght-datagrid-to-Excel.aspx

La solution ci-dessus de David dans Dakota semble un peu plus facile à implémenter, et il y a toujours la redirection vers une page asp.net classique avec une grille de données et le type de contenu défini sur Excel, mais vous avez alors plus de code à prendre en charge peut ne pas fonctionner pour les solutions hors connexion du navigateur qui ne fonctionnent pas.

Quoi qu'il en soit, c'est une tâche commune. J'espère que certains ici ou chez Microsoft proposeront une solution plug and play Mort :)

J'ai trouvé une méthode d'extension pour l'exportation CVS à partir d'une datagrid Silverlight.

http://www.codeproject.com/KB/silverlight/SilverlightDataGridExport.aspx

Il a le potentiel d’être plug-and-play, mais j’ai dû le modifier légèrement pour le faire fonctionner avec des datagrids avec des sources de données d’élément (voir les commentaires dans le post). Quelqu'un de plus brillant et plus expérimenté que moi devrait pouvoir ajuster à la perfection. Jetez-y un coup d'œil, cela devrait vous rapprocher de ce dont vous avez besoin.

1
infocyde

Ces solutions ne fonctionnaient pas pour moi, alors je les ai modifiées pour en faire une qui fonctionne. (Ma solution n'exige pas de guillemets autour des champs, alors j'ai omis la fonction FormatCSVField)

    public void SaveAs(string csvPath)
    {
        string data = ExportDataGrid(true, _flexGrid);
        StreamWriter sw = new StreamWriter(csvPath, false, Encoding.UTF8);
        sw.Write(data);
        sw.Close();
    }

    public string ExportDataGrid(bool withHeaders, Microsoft.Windows.Controls.DataGrid grid) 
    {
        System.Text.StringBuilder strBuilder = new System.Text.StringBuilder();
        System.Collections.IEnumerable source = (grid.ItemsSource as System.Collections.IEnumerable);

        if (source == null) return "";

        List<string> headers = new List<string>();

        grid.Columns.ToList().ForEach(col =>
        {
            if (col is Microsoft.Windows.Controls.DataGridBoundColumn)
            {
                headers.Add(col.Header.ToString());
            }
        });

        strBuilder.Append(String.Join(",", headers.ToArray())).Append("\r\n");
        foreach (Object data in source)
        {
            System.Data.DataRowView d = (System.Data.DataRowView)data;
            strBuilder.Append(String.Join(",", d.Row.ItemArray)).Append("\r\n");
        }

        return strBuilder.ToString();
    }
1
VenerableAgents

Je devais faire la même chose. J'ai utilisé l'implémentation par t3rse, mais j'ai dû apporter quelques modifications. Je n'ai pas assez de réputation pour commenter sa réponse, je vais donc les énumérer ici:

  • Pour la ligne qui dit propInfo.GetValue (data, null) .ToString (), j'ai vérifié si la valeur renvoyée par GetValue est Null avant d'appeler ToString () dessus.

  • Dans la méthode FormatCSVField (), il a remplacé un guillemet double par trois guillemets doubles. Il ne doit le remplacer que par deux guillemets doubles.

  • L'implémentation utilise uniquement des colonnes de type DataGridBoundColumn et en ignore d'autres. J'ai des colonnes qui ne sont pas DataGridBoundColumn que je voulais inclure, donc j'ai obtenu le nom de la propriété de la source de données pour ces colonnes avec col.SortMemberPath.

0
John Gilmer

Voici une approche intéressante qui a fonctionné pour moi http://forums.silverlight.net/forums/p/179321/404357.aspx

0
Fedor