Silverlight DataGrid: экспорт в Excel или CSV - PullRequest
22 голосов
/ 20 ноября 2008

Есть ли способ экспортировать мои данные Silverlight DataGrid в Excel или CSV?

Я искал в Интернете, но не могу найти никаких примеров!

Большое спасибо

Ответы [ 9 ]

21 голосов
/ 03 августа 2009

Silverlight 3 меняет ответ на этот вопрос, поскольку дает возможность пользователю создавать файл на рабочем столе пользователя в указанном им месте. Я адаптировал код, представленный DaniCE, разделил вещи на несколько методов для удобства чтения и использую свободно определенный формат CSV, который должен распознавать Excel.

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();
}
4 голосов
/ 09 декабря 2008

Я нашел это с помощью буфера обмена.

Чтобы сделать код общим, вы можете изменить первый пример, чтобы прочитать привязки столбцов и применить их к данным, используя отражение:

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();
}

конечно, это работает только тогда, когда путь привязки является именем свойства. Для более сложных путей вы должны применить привязку к данным (я полагаю, это было бы лучшим решением, но сейчас я не уверен, как это сделать).

2 голосов
/ 21 ноября 2010

Я знаю, что это старый пост, но он мне помог. Я сделал несколько правок, чтобы он работал с Silverlight 4, конвертировал и выделялся. Я хотел быстрый экспорт, поэтому сначала я использую CSV, а затем открываю его с помощью Excel. Этот код работает в сети Silverlight и обладает повышенным доверием. В Сети не откроется в 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 голосов
/ 20 ноября 2008

Я не думаю, что Silverlight предлагает способ загрузки файлов. Вы можете добавить в свое приложение кнопку, которая вызывает URL-адрес, т. Е. http://www.mysite.com/generateexcelfile.aspx. Включить в качестве значений Querystring параметры, используемые для создания данных, отображаемых в приложении Silverlight, выполнить запрос и использовать свой любимый компонент создания файлов Excel создать файл на лету. Переадресация на него, и он будет загружен в систему пользователей.

1 голос
/ 07 марта 2011

Эти решения не сработали для меня, поэтому я изменил их на тот, который работал. (Мое решение не требует кавычек вокруг полей, поэтому я пропустил функцию 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 голос
/ 03 декабря 2009

Проверьте решение Райана. Выглядит хорошо, не могу ручаться за это, хотя, потому что я только что нашел это. Райан делает то, что запрашивает DLL выше.

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

Решение David in Dakota, описанное выше, выглядит немного проще для реализации, и всегда есть перенаправление на классическую страницу asp.net с сеткой данных и типом контента, настроенным на превосходство, но тогда у вас будет больше кода для поддержки и этот способ может не работать для автономных браузерных решений (которые на самом деле не будут работать).

Во всяком случае, это обычная задача. Я надеюсь, что некоторые люди здесь или в Microsoft придумают решение Mort Plug and Play:)

Я нашел способ расширения для экспорта CVS из таблицы данных Silverlight-

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

Он может быть подключен и работать, но мне пришлось немного настроить его, чтобы он работал с сетями данных с источниками данных элементов (см. Комментарии в посте). Кто-то более яркий и опытный, чем я, должен быть в состоянии настроить к совершенству. Проверьте это, это должно приблизить вас к тому, что вам нужно.

1 голос
/ 04 февраля 2009

От макушки головы я бы сказал, что вы можете добавить кнопку экспорта с помощью ControlTemplate, а затем перебрать каждый элемент в DataSource, а затем использовать каждый столбец в Columns, чтобы получить содержимое каждого ячейка, используя метод GetCellContent, или используйте информацию привязки DataGridColumn, чтобы получить соответствующее значение ячейки. Затем вы можете получить отображаемое значение этого содержимого и записать его в свой отчет.

Что-то вроде ...

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...

   }
}

Или используя информацию о привязке, как описано в DaniCE .

0 голосов
/ 23 октября 2013

Мне нужно было сделать то же самое. Я использовал реализацию t3rse, но мне пришлось внести несколько изменений. У меня недостаточно репутации, чтобы комментировать его ответ, поэтому я перечислю их здесь:

  • Для строки, которая говорит propInfo.GetValue (data, null) .ToString (), я проверил, имеет ли значение, возвращаемое GetValue, значение Null, прежде чем вызывать ToString () для него.

  • В методе FormatCSVField () он заменяет двойные кавычки тремя двойными кавычками. Его следует заменить только двумя двойными кавычками.

  • Реализация использует только столбцы типа DataGridBoundColumn и игнорирует другие. У меня есть столбцы, отличные от DataGridBoundColumn, которые я хотел включить, поэтому я получил имя свойства источника данных для этих столбцов с помощью col.SortMemberPath.

0 голосов
/ 24 мая 2010

Вот хороший подход, который работал для меня http://forums.silverlight.net/forums/p/179321/404357.aspx

...