EvolutivaWinformsUtils 1.0.0

dotnet add package EvolutivaWinformsUtils --version 1.0.0
                    
NuGet\Install-Package EvolutivaWinformsUtils -Version 1.0.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="EvolutivaWinformsUtils" Version="1.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="EvolutivaWinformsUtils" Version="1.0.0" />
                    
Directory.Packages.props
<PackageReference Include="EvolutivaWinformsUtils" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add EvolutivaWinformsUtils --version 1.0.0
                    
#r "nuget: EvolutivaWinformsUtils, 1.0.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package EvolutivaWinformsUtils@1.0.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=EvolutivaWinformsUtils&version=1.0.0
                    
Install as a Cake Addin
#tool nuget:?package=EvolutivaWinformsUtils&version=1.0.0
                    
Install as a Cake Tool

EvolutivaWinformsUtils

Controles y utilidades reutilizables para aplicaciones Windows Forms.

La solución compila para .NET Framework 4.8 y .NET 10 Windows.

NumericTextBox

Control numérico para valores enteros y decimales.

using EvolutivaWinformsUtils.Controls.NumericTextBox;

numericTextBox.NumericType = NumericTextBoxType.Decimal;
numericTextBox.DecimalPlaces = 2;
numericTextBox.Minimum = 0;
numericTextBox.Maximum = 10000;
numericTextBox.Value = 1234.56m;

La validación no bloquea el cambio de foco. Los valores inválidos se indican visualmente y mediante ErrorProvider.

EvolutivaDataGridView

DataGridView con una configuración visual y de comportamiento adecuada para grillas de consulta:

  • Double buffering habilitado.
  • Solo lectura por defecto.
  • Sin fila automática para nuevos registros.
  • Sin encabezados de fila.
  • Sin borde.
  • Selección por celda.
  • Copiado incluyendo encabezados.
  • Encabezados centrados.
  • Filas de 26 píxeles.
using EvolutivaWinformsUtils.Controls.DataGridView;

var grid = new EvolutivaDataGridView();
grid.ConfigureGrid<Movimiento>(ColumnDefinitions.New()
    .Hidden("Id")
    .DateTime("Fecha", "Fecha")
    .String("Descripcion", "Descripción").Fill()
    .Integer("Cantidad")
    .Decimal("Importe"));

grid.DataSource = movimientos;

La grilla puede mostrar un totalizador integrado en su parte inferior. La propiedad ShowTotalizer controla su visibilidad y SumColumnName indica la columna numérica que se debe sumar. El totalizador muestra seleccionados / totales tanto para registros como para la suma:

grid.ShowTotalizer = true;
grid.SumColumnName = "Importe";
grid.TotalizerNumberFormat = "N2";

La selección se calcula sobre las filas que tienen al menos una celda seleccionada y se actualiza automáticamente al cambiar la selección o el contenido de la grilla.

Proyecto de ejemplo

Samples muestra el uso de:

  • NumericTextBox.
  • EvolutivaDataGridView.
  • ColumnDefinitions y ConfigureGrid.

El CRUD de la grilla utiliza MySQL de forma persistente. La cadena de conexión del proyecto de prueba se configura en Samples/appsettings.Development.json, que está excluido de Git:

{
  "ConnectionStrings": {
    "DefaultConnection": "Server=localhost;Port=3306;Database=analytics;User ID=datalink;Password=change-me;"
  }
}

Luego ejecute:

dotnet run --project .\Samples\Samples.csproj

El ejemplo utiliza las tablas existentes products y orders de la base analytics; no modifica el esquema al iniciar. El script de referencia Samples/Database/Scripts/001_CreateProductsAndOrders.sql contiene el esquema y los datos iniciales compartidos.

La grilla consulta productos, muestra el precio y la cantidad de órdenes asociadas; el totalizador suma la columna Price. La muestra también incluye los formularios y botones necesarios para extender el ejemplo con operaciones de alta, edición y eliminación mediante el repositorio.

Si la base ya tenía creadas las tablas sin la columna price, ejecute una vez Samples/Database/Scripts/002_AddPriceToProducts.sql antes de consultar.

SearchLookup

SearchLookup es un control WinForms para buscar y seleccionar registros de una colección sin desplegar toda la lista como un ComboBox. Está disponible en el namespace:

using EvolutivaWinformsUtils.Controls.SearchLookup;

El paquete unificado se instala con:

dotnet add package EvolutivaWinformsUtils

Publicación en NuGet.org

La publicación se realiza mediante GitHub Actions y Trusted Publishing con OIDC. El workflow se ejecuta al crear un tag con formato v*:

git tag v1.0.0
git push origin v1.0.0

En NuGet.org se debe crear una política de Trusted Publishing para:

  • Owner: toledomatias
  • Repository: EvolutivaWinformsUtils
  • Workflow file: publish.yml
  • Environment: dejar vacío

La versión publicada debe coincidir con la propiedad Version del proyecto.

Ejemplo básico:

var lookup = new SearchLookup
{
    DataSource = tiposIva,
    ValueMember = "Codigo",
    DisplayMember = "Descripcion",
    SearchMembers = new[] { "Codigo", "Descripcion" },
    MaxResults = 30
};

lookup.SelectedValueChanged += (_, _) =>
{
    var tipo = (TipoIva?)lookup.SelectedItem;
    // Usar tipo seleccionado.
};

Las propiedades AdditionalMembers y AdditionalHeaders permiten mostrar columnas adicionales en el resultado. ShowValueColumn permite ocultar la columna de código cuando la selección se realiza únicamente por descripción. La búsqueda se realiza en tiempo real y admite navegación con , , Enter y Escape.

SqlHelper

SqlHelper simplifica el acceso a tablas mediante mappings fluent, consultas con Dapper y repositorios reutilizables. Sus tipos están disponibles en el namespace:

using EvolutivaWinformsUtils.Persistence.SqlHelper;

Configuración de mappings

MappingRegistry es el punto de entrada para definir y registrar las tablas. Si no se indica el nombre físico de una tabla, se utiliza el nombre de la clase convertido a snake_case. Los nombres de columnas también se deducen automáticamente convirtiendo PascalCase a snake_case, aunque pueden indicarse explícitamente.

var mappings = new MappingRegistry()
    .AddTable<Department>() // usa "department"
        .AutoIncrementKey(x => x.Id)
        .Field(x => x.Name)
    .AddTable<Category>("categories")
        .AutoIncrementKey(x => x.Id)
        .Field(x => x.Name)
        .Field(x => x.DepartmentId)
            .ForeignKey<Department>()
    .AddTable<Product>("products")
        .AutoIncrementKey(x => x.Id)
        .Field(x => x.Name)
        .Field(x => x.Price)
        .Field(x => x.Active)
        .Field(x => x.CategoryId)
            .ForeignKey<Category>()
        .Calculated(x => x.OrderCount,
            "(SELECT COUNT(*) FROM orders o WHERE o.product_id = @Prefijo.id)");

Cada foreign key se representa en la entidad mediante el campo escalar y la propiedad de navegación:

public class Category
{
    public int Id { get; set; }
    public string Name { get; set; } = "";
    public int DepartmentId { get; set; }
    public Department Department { get; set; } = null!;
}

Inyección de dependencias

El registry, la fábrica de conexiones y el repositorio pueden registrarse en el contenedor de dependencias:

services.AddSingleton(mappings);
services.AddSingleton<IConnectionFactory>(
    new ConnectionFactory(connectionString, () => new MySqlConnection()));
services.AddTransient<Repository<Product>>();

El repositorio recibe el mapping centralizado y la fábrica de conexiones:

public class ProductsForm : Form
{
    private readonly Repository<Product> repository;

    public ProductsForm(Repository<Product> repository)
    {
        InitializeComponent();
        this.repository = repository;
    }
}

Consultas, filtros y relaciones

Las consultas se construyen encadenando filtros, ordenamientos y joins. Los tipos de las entidades relacionadas se infieren desde los mappings, por lo que ToList() no necesita recibir tipos genéricos adicionales.

var products = repository.Query("p")
    .AddJoin("p", "category_id", "c")
    .AddJoin("c", "department_id", "d")
    .Where("p.active = @Activo", new { Activo = true })
    .OrderBy("p.name ASC")
    .ToList();

La materialización automática asigna las propiedades navegacionales:

Product
└── Category
    └── Department

La misma operación está disponible de forma asíncrona mediante ToListAsync().

Campos calculados

Los campos calculados no se incluyen por defecto. Esto evita ejecutar innecesariamente subconsultas costosas como COUNT o SUM.

var products = repository.Query("p")
    .IncludeCalculated(x => x.OrderCount)
    .OrderBy("p.name ASC")
    .ToList();

Solo se ejecutan los cálculos solicitados explícitamente mediante IncludeCalculated(...).

CRUD

var product = new Product
{
    Name = "Monitor",
    Price = 250.00m,
    Active = true,
    CategoryId = 2
};

repository.Insert(product);
// product.Id contiene la clave generada por la base de datos.

product.Price = 275.00m;
repository.Update(product);
repository.Delete(product);

También existen las operaciones InsertAsync, UpdateAsync, DeleteAsync y GetByIdAsync.

Product Compatible and additional computed target framework versions.
.NET net10.0-windows7.0 is compatible. 
.NET Framework net48 is compatible.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETFramework 4.8

  • net10.0-windows7.0

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.0.0 82 9/10/2026