2008-11-20 24 views

Respuesta

2

No creo Silverlight ofrece una manera de descargar archivos. Puede agregar un botón a su aplicación que llame a una URL, es decir, http://www.mysite.com/generateexcelfile.aspx. Incluya como valores de Querystring los parámetros utilizados para generar los datos que se muestran en su aplicación Silverlight, ejecute su consulta y use su componente favorito de generación de archivos de Excel para generar el archivo sobre la marcha. Redirigir a él y se descargará en el sistema de los usuarios.

+3

Tenga cuidado con "crear el archivo y luego redirigir a él" - tiene que eliminar estos archivos en algún momento. Lo mejor sería simplemente guardar el Excel en la secuencia de salida de la página .aspx con el tipo de mime correcto, para que el navegador pueda ver que es un archivo de Excel, no una página html, y darle al usuario la opción de guardarlo . – user8032

4

He encontrado this usando el portapapeles.

Para hacer que el código genérico se puede modificar el primer ejemplo de leer los enlaces de la columna y aplicar que a los datos utilizando la reflexión:

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

por supuesto, sólo funciona cuando el camino de la unión es la nombre de la propiedad. Para rutas más avanzadas, debe aplicar el enlace a los datos (supongo que sería una mejor solución, pero no estoy seguro de cómo hacerlo ahora).

1

De la parte superior de mi cabeza, diría que se puede añadir el botón de exportación utilizando un ControlTemplate y luego iterar sobre cada elemento de la DataSource, y luego usar cada columna de Columns para obtener el contenido de cada celda utilizando el método GetCellContent o utilice la información de enlace de DataGridColumn para obtener el valor de celda apropiado. A continuación, puede obtener el valor mostrado de este contenido y escribirlo en su informe.

Algo así como ...

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

    } 
} 

O usando la información de enlace como se describe por DaniCE.

21

Silverlight 3 cambia la respuesta a esta pregunta porque permite al usuario crear un archivo en el escritorio del usuario en la ubicación que especifique. Adapté el código presentado por DaniCE, dividí las cosas en unos pocos métodos para la legibilidad y estoy usando un formato CSV poco definido que Excel debería reconocer.

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

¿Esto funciona? – Goober

+1

Lo hace con algunos juegos de manos; crea un archivo CSV, no XLS. Si una persona tiene Excel instalado, lo abre en virtud de la extensión asignada a Excel. – t3rse

+1

Si obtiene un error en la línea de enlace, intente enviar de esta manera: binding = (System.Windows.Data.Binding) ((Microsoft.Windows.Controls.DataGridBoundColumn) col) .Binding; – proudgeekdad

1

Compruebe la solución de Ryan. Se ve bien, no puedo asegurarlo porque lo acabo de encontrar. Ryan hace lo que DLL solicitó anteriormente.

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

David en solución de Dakota anterior se ve un poco más fácil de implementar, y siempre existe la redirección a una página asp.net clásico con una cuadrícula de datos en él y el tipo de contenido establecido para sobresalir, pero luego tiene más código para admitir y de esa manera puede no funcionar para las soluciones fuera de navegador que están fuera de línea (en realidad no funcionarán).

De todos modos, esta es una tarea común.Espero que algunas personas aquí o en Microsoft llegar a un Mort plug and play solución :)

he encontrado un método de extensión para CVS exportación desde un Silverlight datagrid-

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

Tiene el potencial de ser plug and play, pero tuve que cambiarlo un poco para que funcione con datagrids con fuentes de datos de elementos (ver comentarios en la publicación). Alguien más brillante y con más experiencia que yo debería ser capaz de modificar a la perfección. Compruébalo, debería acercarte a lo que necesitas.

2

Sé que esto es una entrada antigua, pero me ayudó. He hecho algunas ediciones para que funcione con silverlight 4, convierte y excel. Quería la exportación rápida, así que primero uso CSV y luego lo abro con Excel. Este código funciona en la web de Silverlight y ofrece una confianza elevada. En la web no se abrirá en 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(); 
    } 
+0

Gracias se ve bien vamos a intentarlo. Quite su complemento, consulte aquí http://stackoverflow.com/faq#signatures –

+0

Solo una nota para indicar que controlar Excel a través de la interoperabilidad de esta manera requiere que el usuario se esté ejecutando fuera del navegador (OOB). También debe compilar su aplicación para que solicite permisos elevados (a través de las páginas de propiedades del proyecto). –

1

Esas soluciones no me funcionaron, así que las modifiqué a una que funcionó. (Mi solución no requiere comillas alrededor de los campos, por lo que queda fuera de la función 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(); 
    } 
0

que tenía que hacer lo mismo. Usé la implementación t3rse, pero tuve que hacer algunos cambios. No tengo la reputación suficiente para hacer un comentario en su respuesta, así que voy a enumerarlos aquí:

  • Para la línea que dice propInfo.GetValue (datos, null) .ToString(), he comprobado a ver si el valor devuelto por GetValue es nulo antes de llamar a ToString() en él.

  • En el método FormatCSVField(), reemplazó una comilla doble con tres comillas dobles. Solo debería reemplazarlo con dos comillas dobles.

  • La implementación solo utiliza columnas de tipo DataGridBoundColumn e ignora otras. Tengo columnas que no son DataGridBoundColumn que quería incluir, así que obtuve el nombre de propiedad de la fuente de datos para esas columnas con col.SortMemberPath.