ClosedXML, una manera fácil de dar formato a nuestros .xlsx

Tiempo de lectura: 5 minutos

closedxml

Hace ya unos meses que empezamos en este blog, con una entrada sobre ClosedXML, pero si que es cierto, que se puedo quedar un poco corta, aunque daba las ideas más básicas. Hoy, vamos a ampliar esa pequeña píldora sobre ClosedXML aprendiendo a dar formato a nuestras hojas.

Nuestro objetivo

Vamos a intentar hacer una tabla de colores como la que tenemos a continuación:

Resultado ClosedXML

Creación del proyecto

Por cambiar un poco desde de la primera parte, vamos a crear un proyecto en .NetCore (ahora que también sabemos instalar el framework en linux o como depurar sobre SSH), para ello, creamos un proyecto de consola:

consola .net core

O desde el CLI de NetCore:

dotnet new console

Lo siguiente que tenemos que hacer es añadir el paquete ClosedXML a través de nuget. Esto se puede hacer a través de la «Consola de Administrador de Paquetes» con el comando:

PM->Install-Package ClosedXML

O también desde el CLI de NetCore:

dotnet add package ClosedXML

Como siempre, utilizando el administrador que integra VS:

nuget

Generando y formateando el fichero con ClosedXML

Teniendo claro el objetivo, vamos a ponernos con en faena y analizar el código que hemos utilizado:

 
using ClosedXML.Excel;
using System.Collections.Generic;

namespace PostClosedXML2
{
  class Program
  {    
    static IEnumerable GetColors()
    {
      yield return XLColor.Red;
      yield return XLColor.Amber;
      yield return XLColor.AppleGreen;
      yield return XLColor.AtomicTangerine;
      yield return XLColor.BallBlue;
      yield return XLColor.Bittersweet;
      yield return XLColor.CalPolyPomonaGreen;
      yield return XLColor.CosmicLatte;
      yield return XLColor.DimGray;
      yield return XLColor.ZinnwalditeBrown;
    }

    static void Main(string[] args)
    {
      using (var workbook = new XLWorkbook())
      {
        //Generamos la hoja
        var worksheet = workbook.Worksheets.Add("FixedBuffer");
        //Generamos la cabecera
        worksheet.Cell("A1").Value = "Nombre";
        worksheet.Cell("B1").Value = "Color";

        //-----------Le damos el formato a la cabecera----------------
        var rango = worksheet.Range("A1:B1"); //Seleccionamos un rango
        rango.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thick); //Generamos las lineas exteriores
        rango.Style.Border.SetInsideBorder(XLBorderStyleValues.Medium); //Generamos las lineas interiores
        rango.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; //Alineamos horizontalmente
        rango.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;  //Alineamos verticalmente
        rango.Style.Font.FontSize = 14; //Indicamos el tamaño de la fuente
        rango.Style.Fill.BackgroundColor = XLColor.AliceBlue; //Indicamos el color de background
        

        //-----------Genero la tabla de colores-----------
        int nRow = 2;
        foreach (var color in GetColors())
        {
          worksheet.Cell(nRow, 1).Value = color.ToString(); //Indicamos el valor en la celda nRow, 1
          worksheet.Cell(nRow, 2).Style.Fill.BackgroundColor = color; //Cambiamos el color de background de la celda nRow,2
          nRow++;
        }

        //Aplico los formatos
        rango = worksheet.Range(2, 1, nRow-1, 2); //Seleccionamos un rango
        rango.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thick); //Generamos las lineas exteriores
        rango.Style.Border.SetInsideBorder(XLBorderStyleValues.Medium); //Generamos las lineas interiores
        rango.Style.Font.SetFontName("Courier New"); //Utilizo una fuente monoespacio
        rango.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Right; //Alineamos horizontalmente
        rango.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;  //Alineamos verticalmente


        worksheet.Columns(1, 2).AdjustToContents(); //Ajustamos el ancho de las columnas para que se muestren todos los contenidos

        workbook.SaveAs("CellFormating.xlsx");  //Guardamos el fichero
      }
    }
  }
}

Lo primero de todo, hemos creado una lista con los colores que queremos utilizar para nuestra tabla. Para ello, utilizamos los colores propios del paquete, que trae una lista enorme de colores:

 
static IEnumerable GetColors()
{
  yield return XLColor.Red;
  yield return XLColor.Amber;
  yield return XLColor.AppleGreen;
  yield return XLColor.AtomicTangerine;
  yield return XLColor.BallBlue;
  yield return XLColor.Bittersweet;
  yield return XLColor.CalPolyPomonaGreen;
  yield return XLColor.CosmicLatte;
  yield return XLColor.DimGray;
  yield return XLColor.ZinnwalditeBrown;
}

Una vez que tenemos eso controlado, vamos a entrar al jugo del código. En primero lugar, podemos ver que todo el código esta dentro de un using:

 
using (var workbook = new XLWorkbook())
{
   //Código
}

Con esto conseguimos que los recursos utilizados para generar el fichero se liberen correctamente al acabar de usarlos. Lo siguiente que vemos, es como generamos la hoja dentro del libro:

 
//Generamos la hoja
var worksheet = workbook.Worksheets.Add("FixedBuffer");

Una vez que tenemos la hoja creada, añadimos las dos primeras celdas que nos servirán de cabecera para la tabla:

 
//Generamos la cabecera
worksheet.Cell("A1").Value = "Nombre";
worksheet.Cell("B1").Value = "Color";

Vamos a darle formato a la cabecera de la tabla:

 
//-----------Le damos el formato a la cabecera----------------
var rango = worksheet.Range("A1:B1"); //Seleccionamos un rango
rango.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thick); //Generamos las lineas exteriores
rango.Style.Border.SetInsideBorder(XLBorderStyleValues.Medium); //Generamos las lineas interiores
rango.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Center; //Alineamos horizontalmente
rango.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;  //Alineamos verticalmente
rango.Style.Font.FontSize = 14; //Indicamos el tamaño de la fuente
rango.Style.Fill.BackgroundColor = XLColor.AliceBlue; //Indicamos el color de background

Para trabajar con mayor comodidad, seleccionamos un rango (A1:B1), de modo que todo lo que hagamos sobre el rango, se va a aplicar a todas las celdas del rango, en este caso a A1 y a B1. Lo que hacemos es asignarle los bordes extreriores e interiores, alinear el contenido horizontal y verticalemnte, le modificamos el tamaño de la fuente, y por ultimo, pintamos el color de fondo. Sin ningun problema, generamos la tabla de colores:

 

//-----------Genero la tabla de colores-----------
int nRow = 2;
foreach (var color in GetColors())
{
    worksheet.Cell(nRow, 1).Value = color.ToString(); //Indicamos el valor en la celda nRow, 1
    worksheet.Cell(nRow, 2).Style.Fill.BackgroundColor = color; //Cambiamos el color de background de la celda nRow,2
    nRow++;
}

Como en casos anteriores, asignamos un valor a una celda, y un backcolor a la otra. Con esto, solo nos queda aplicar los formatos y guardar. Vamos a aplicar los formatos:

 
//Aplico los formatos
    rango = worksheet.Range(2, 1, nRow-1, 2); //Seleccionamos un rango
    rango.Style.Border.SetOutsideBorder(XLBorderStyleValues.Thick); //Generamos las lineas exteriores
    rango.Style.Border.SetInsideBorder(XLBorderStyleValues.Medium); //Generamos las lineas interiores
    rango.Style.Font.SetFontName("Courier New"); //Utilizo una fuente monoespacio
    rango.Style.Alignment.Horizontal = XLAlignmentHorizontalValues.Right; //Alineamos horizontalmente
    rango.Style.Alignment.Vertical = XLAlignmentVerticalValues.Center;  //Alineamos verticalmente

Pero ojo, esta vez, hemos asignado también la fuente:

 
rango.Style.Font.SetFontName("Courier New");

Esto lo hacemos para que la tabla nos quede perfectamente cuadrada al utilizar letras monoespacio. Por ultimo, queremos que las celdas se queden perfectamente a la vista todas, aunque el contenido sea mayor que el ancho de la columna, por lo tanto, vamos a ajustar el ancho de columnas. Eso lo hacemos con:

 
worksheet.Columns(1, 2).AdjustToContents(); //Ajustamos el ancho de las columnas para que se muestren todos los contenidos

Lo que conseguimos así, es que el ancho de las columnas 1 y 2, se ajuste de modo que se vea el contenido de todas las celdas. Con todo hecho, simplemente guardamos:

 
workbook.SaveAs("CellFormating.xlsx");  //Guardamos el fichero

Y al abrir el excel, veremos que se nos ha quedado una tabla como la que presentábamos al principio. Como siempre, si queréis probar el código fuente, os dejo el enlace al repositorio de GitHub. Esto solo es una pequeña pincelada de todo los que se puede conseguir con ClosedXML y con OpenXML en general. En futuras entradas, seguiremos ampliando su uso.

14 comentarios en «ClosedXML, una manera fácil de dar formato a nuestros .xlsx»

  1. Estimado, gracias por su post, me ha ayudado muchísimo: llevo poco iempo en la programación. Tengo una pequeña App en C# que realiza exportaciones a Excel, para lo cual utilizaba Microsoft.Office.Interop.Excel. Por algunas inconvenientes con esta biblioteca, estoy pasando el código a ClosedXML, pero me choco con un problema y me gustaría pudieras ayudarme. El prooceso de exportado lo tengo dividido por etapas, donde lleno los datos principales, en otro lleno encabezados en otro aplico formatos, etc. y al final cierro el libro y lo guardo. Lo que hago es que de un método otro paso como parámetro la Hoja que quiero modificar. ¿Hay manera de crear una variable al inicio de la clase y utilizarla en cada uno de los métodos?

    Responder
    • Buenas Sergio,
      Puedes hacer que la hoja que quieres modificar sea una variable privada miembro de la clase y que se utilice en los métodos en lugar de la que recibes como parámetro.
      Una vez tienes eso solo te falta como inicializar esa variable miembro. Si ahora la inicializas en el primer método, lo puedes hacer igual. Si en cambio el primer método también la recibe como parámetro, lo que puedes hacer es crear un método extra que reciba la hoja como parámetro y la asigne a la variable miembro.
      Espero haber resuelto tus dudas, sino, lo mejor es que me escribas a través de la sección de contacto (así solo lo veo yo) con el código de la clase y te ayudo a cambiarla.
      Un abrazo!!

      Responder
  2. utilizo closedxml para editar una plantilla de excel, lo que hago es copiarla con file.copy a un nuevo lugar y esa nueva que se crea es la que le inserto los datos, pero el problema es que la plantilla viene con un origen de datos xml y cuando abro el excel y me voy a la pestaña de programador – origen de datos, veo que solo la primera hoja esta asociado a las variables de mapa xml, y las demas hojas con sus celdas no estan asociadas, solo ocurre cuando inserto los datos, cuando solo hago File.Copy permanece cada celda de cada hoja con su origen de datos. Como hago que al llenar los datos eso no me cambie?

    Responder
    • Hola Nathaly,
      En primer lugar, disculpa la espera (estas fiestas he desconectado del todo) y gracias por tu comentario!!!
      La verdad es que no acabo de entender cual es tu problema, ¿ qué al usar System.IO.File.Copy() no te esta respetando los orígenes de datos que tenias configurados ? Lo mejor si te parece es que me escribas a la sección de contacto y desde ahí hablamos por email, así me puedes enviar el código que te esta fallando y le echo un ojo.
      Feliz Año!

      Responder
  3. Hola compa

    una duda tonta, si añado el paquete ClosedXML en mi maquina para un proyecto, posteriormente creo la publicacion que levantare en algun servidor web, va mi duda: ¿se requiere instalar en dicho servidor el closedxml o al generar la publicacion se van automaticamente las dlls requeridas?

    Responder
    • Buenas Rolando,
      No necesitas instalar nada en el servidor 🙂
      Lo bueno de ClosedXML (o de cualquier implementación de OpenXML que uses) no trabajan directamente con la interoperabilidad de excel sino que implementan el standard y con eso trabajan.
      Precisamente este es el punto bueno, no necesitas instalar en el servidor un excel que no vas a usar más que para generar en background cosas.

      Un saludo!

      Responder

Deja un comentario