Patrones de uso
Cookbook de DinaZen: cinco recetas de extremo a extremo para leer datos del SDK, pintarlos, elegir el selector correcto, montar diálogos y gestionar la carga.
Recetas que copias y adaptas, no referencia de props. Cada una resuelve un problema real de montar una app Blazor sobre el SDK .NET: traer datos con el Cliente Dinaup y pintarlos con DinaZen sin reinventar la UI.
El reparto es siempre el mismo: el cliente trae el dato, DinaZen lo pinta. Si una receta te pide un DinaupClientC, viene de crear y conectar el cliente.
De un informe a una tabla
Tienes un informe de Dinaup Flex (su GUID) y quieres pintar sus filas en una tabla con paginación, búsqueda, filtros y exportación a CSV. Sin escribir ni una columna a mano. DnzReportView ejecuta el informe contra la API con tu cliente y genera el DataGrid a partir de la definición del informe.
Crea y conecta el cliente
@code {
private DinaupClientC _client;
protected override async Task OnInitializedAsync()
{
_client = new DinaupClientC(endpoint, apiKey, secretKey, "*");
await _client.InitializeAsync(3000);
}
}Pinta el informe inline
Pásale el cliente y el GUID del informe. Las columnas, los tipos y los formatos los deduce solo de la definición del informe.
@if (_client.IsNotNull())
{
<div style="height:600px; overflow:auto;">
<DnzReportView Client=@_client ReportId="guid-del-informe" Limit="50" />
</div>
}Reacciona al clic en una fila
Por defecto, al pulsar una fila el componente abre la ficha del registro. Si quieres tu propio comportamiento, captura OnItemSelect.
<DnzReportView Client=@_client ReportId="guid-del-informe" OnItemSelect=@AbrirDetalleAsync />
@code {
private async Task AbrirDetalleAsync(DinaupDynamicRowDTO row)
{
// row.ID y row.SectionId vienen rellenos
await HacerAlgoCon(row.ID);
}
}No necesitas leer las filas tú mismo: DnzReportView llama a Client.Report_GetAsync por dentro, gestiona la carga, los errores y la paginación del lado servidor. Tú solo pones cliente y GUID.
¿Lo quieres en un diálogo o en una ventana flotante en lugar de inline? El componente expone dos helpers estáticos.
@inject DialogService DialogService
@code {
private async Task AbrirInformeAsync()
{
await DnzReportView.OpenAsync(DialogService, _client, "guid-del-informe", title: "Ventas del mes");
}
}@inject DnzWindowManagerService WindowManager
@code {
private void AbrirInformeEnVentana()
{
DnzReportView.OpenAsWindow(WindowManager, _client, "guid-del-informe", title: "Ventas");
}
}Firmas de los helpers estáticos:
Task DnzReportView.OpenAsync(DialogService ds, DinaupClientC client, string reportId, Dictionary<string, string> vars = null, string title = "Informe", string width = "90%", string height = "80%")
string DnzReportView.OpenAsWindow(DnzWindowManagerService wm, DinaupClientC client, string reportId, Dictionary<string, string> vars = null, string title = "Informe", string icon = "analytics")DnzReportView
Ejecuta un informe de Flex y lo pinta como tabla con búsqueda, filtros, paginación servidor y exportación a CSV.
<DnzReportView Client=@_client ReportId="guid-del-informe" Limit="50" Title="Ventas" />Parámetros
| Parámetro | Tipo | Por defecto | Qué hace |
|---|---|---|---|
Client | DinaupClientC | — | Obligatorio. Cliente del SDK ya inicializado. |
ReportId | string | "" | Obligatorio. GUID del informe a ejecutar. |
VariablesValues | Dictionary<string, string> | null | Valores para las variables del informe. |
QuerySearch | string | "" | Búsqueda textual inicial. |
AdvancedFilter | List<FilterCondition> | null | Filtros avanzados aplicados de entrada. |
Limit | int | 50 | Filas por página. |
Orden | Dictionary<string, bool> | null | Orden inicial (clave = columna, valor = ascendente). |
ShowTitle | bool | true | Muestra la cabecera con título e icono de la sección. |
Title | string | "" | Sobrescribe el título; si está vacío, usa el del informe. |
ShowSearch | bool | true | Muestra la caja de búsqueda. |
Filtrable | bool | true | Permite filtrar las columnas. |
ShowAdd | bool | true | Muestra el botón de añadir registro. |
AdminMode | bool | false | Ejecuta el informe en modo administrador. |
ToolBarTemplate | RenderFragment | null | Contenido extra en la barra de herramientas. |
OnItemSelect | EventCallback<DinaupDynamicRowDTO> | — | Se dispara al seleccionar una fila (sustituye al comportamiento por defecto). |
OnDataChanged | EventCallback | — | Se dispara cuando los datos se recargan. |
DnzReportProvider
Variante "headless": ejecuta el informe y expone las filas como CascadingValue, pero no pinta ninguna tabla. Úsalo cuando quieras los datos del informe pero con tu propio render (tarjetas, KPIs, una vista a medida). El ChildContent recibe el contexto con las filas ya cargadas.
<DnzReportProvider Client=@_client ReportId="guid-del-informe" Limite="500">
<div class="d-flex flex-column gap-2">
@* Aquí pintas las filas a tu manera, leyéndolas del CascadingValue *@
</div>
</DnzReportProvider>Parámetros
| Parámetro | Tipo | Por defecto | Qué hace |
|---|---|---|---|
Client | DinaupClientC | — | Obligatorio. Cliente del SDK ya inicializado. |
ReportId | string | "" | Obligatorio. GUID del informe a ejecutar. |
VariablesValues | Dictionary<string, string> | null | Valores para las variables del informe. |
QuerySearch | string | "" | Búsqueda textual inicial. |
AdvancedFilter | List<FilterCondition> | null | Filtros avanzados aplicados de entrada. |
Limite | int | 500 | Máximo de filas a traer. |
Orden | Dictionary<string, bool> | null | Orden inicial (clave = columna, valor = ascendente). |
AdminMode | bool | false | Ejecuta el informe en modo administrador. |
ChildContent | RenderFragment | null | Tu render, que lee las filas del contexto en cascada. |
OnDataLoaded | EventCallback | — | Se dispara cuando las filas terminan de cargar. |
Mostrar datos tipados
Tienes una fila con un importe, una fecha, unos minutos... y quieres pintarlos con el formato correcto (moneda local, fecha amigable, color según el signo) sin formatear a mano. La familia de Spans lo hace: cada uno sabe formatear su tipo según la región del cliente.
<div class="d-flex flex-column gap-2">
<DnzSpanMoney Amount=@factura.Total Label="Total" Icon="payments" AutoColor=true />
<DnzSpanDate Value=@factura.Vencimiento ShowStatus=true />
</div>El truco de AutoColor. En DnzSpanMoney, AutoColor=true pinta el importe en verde si es positivo y en rojo si es negativo. Si solo quieres una de las dos reglas, usa AutoColorGreen o AutoColorRed por separado.
DnzSpanMoney
Pinta un importe con el formato de moneda de la región del cliente. Opcionalmente con etiqueta, icono y color por signo.
<DnzSpanMoney Amount=@total Label="Total" Icon="payments" AutoColor=true />Parámetros
| Parámetro | Tipo | Por defecto | Qué hace |
|---|---|---|---|
Amount | decimal? | 0 | Importe a mostrar. Si es nulo, no pinta nada. |
Label | string | "" | Etiqueta encima del importe. |
Icon | string | "" | Icono Material a la izquierda (requiere Label). |
AutoColor | bool | false | Verde si positivo, rojo si negativo. |
AutoColorGreen | bool | false | Solo verde cuando es positivo. |
AutoColorRed | bool | false | Solo rojo cuando es negativo. |
IsVisible | bool | true | Oculta el componente si es false. |
CssClass | string | "" | Clases CSS extra en el span del importe. |
FontSize | string | "16px" | Tamaño de fuente del importe. |
DnzSpanDate
Pinta una fecha con el formato amigable de la región, con tooltip de la fecha exacta y un badge de estado opcional ("Hoy", "Mañana", "Ayer", "Pasado", "Futuro").
<DnzSpanDate Value=@pedido.Fecha ShowStatus=true />Parámetros
| Parámetro | Tipo | Por defecto | Qué hace |
|---|---|---|---|
Value | DateOnly? | null | Fecha a mostrar. Si es nula, no pinta nada. |
FriendlyMode | bool | true | Usa el formato amigable de la región. |
ShowBadge | bool | false | Pinta la fecha dentro de un badge. |
ShowStatus | bool | false | Añade un badge de color con el estado relativo a hoy. |
Class | string | "" | Clases CSS extra en el contenedor. |
FontSize | string | "0.875rem" | Tamaño de fuente. |
Hay un Span por cada tipo de dato: DnzSpanDateTime, DnzSpanDecimal, DnzSpanInteger, DnzSpanPercent, DnzSpanMinutes, DnzSpanGrams, DnzSpanBytes, DnzSpanGigaBytes, DnzSpanKV. Todos siguen el mismo patrón: les pasas el valor crudo y ellos formatean.
Elegir el selector correcto
Necesitas un desplegable para que el usuario elija un valor. DinaZen tiene tres, y cada uno resuelve un caso distinto. La regla de los tres segundos:
- ¿Es un
enum? →DnzEnumDropDown. Saca las opciones del propio tipo. - ¿La lista ya está en memoria? (la cargaste antes, son pocas) →
DnzDataGridDropDown. Desplegable con búsqueda y columnas. - ¿Hay que buscar/crear una ficha remota? (clientes, productos, miles de registros) →
DnzRowSelector. Busca contra un informe en el servidor mientras escribes.
El binding es @bind-Value sobre tu enum. Las opciones salen solas del tipo.
<DnzEnumDropDown TEnum="EstadoPedidoE" @bind-Value=@_estado Placeholder="Estado" />
@code {
private EstadoPedidoE _estado;
}El binding es @bind-Value sobre un objeto que implemente IDinaupRow. Le pasas la lista por Data y le dices qué propiedad mostrar con TextProperty.
<DnzDataGridDropDown T="ClienteRow" @bind-Value=@_cliente Data=@_clientes TextProperty="Label" Label="Cliente" Width="320px" />
@code {
private ClienteRow _cliente;
private List<ClienteRow> _clientes = new();
}El binding es @bind-SelectedRow. Le pasas el cliente y el GUID del informe contra el que busca; el desplegable consulta el servidor según escribes.
<DnzRowSelector Client=@_client ReportId="guid-informe-clientes" @bind-SelectedRow=@_clienteSel Label="Cliente" Placeholder="Buscar cliente..." />
@code {
private IDinaupRow _clienteSel;
}DnzEnumDropDown
Desplegable cuyas opciones salen de un enum. La etiqueta de cada opción se toma del atributo [Display(Name = ...)] si existe; si no, del nombre del valor.
<DnzEnumDropDown TEnum="EstadoPedidoE" @bind-Value=@_estado />Parámetros
| Parámetro | Tipo | Por defecto | Qué hace |
|---|---|---|---|
Value | TEnum | — | Valor seleccionado. Usa @bind-Value. |
Name | string | "" | Nombre del campo (para formularios). |
Style | string | "width:200px" | Estilo CSS del desplegable. |
Placeholder | string | "" | Texto cuando no hay selección. |
Disabled | bool | false | Desactiva el control. |
Acepta además atributos extra que se pasan tal cual al elemento raíz.
DnzDataGridDropDown
Desplegable con búsqueda y columnas para una lista que ya tienes en memoria. El tipo T debe implementar IDinaupRow.
<DnzDataGridDropDown T="ClienteRow" @bind-Value=@_cliente Data=@_clientes TextProperty="Label" Label="Cliente" />Parámetros
| Parámetro | Tipo | Por defecto | Qué hace |
|---|---|---|---|
Value | T | — | Elemento seleccionado. Usa @bind-Value. |
Data | IEnumerable<T> | lista vacía | Origen de datos en memoria. |
TextProperty | string | null | Requerido. Propiedad a mostrar como texto. |
ColorProperty | string | null | Propiedad que da color de badge a cada opción. |
IconoProperty | string | null | Propiedad que aporta el icono de cada opción. |
Label | string | null | Etiqueta del campo. |
Icon | string | null | Icono a la izquierda del campo. |
Width | string | "280px" | Ancho del control. |
Style | string | null | Estilo CSS extra. |
Visible | bool | true | Muestra u oculta el control. |
IsRequired | bool | false | Marca el campo como obligatorio. |
Disabled | bool | false | Desactiva el control. |
OpenInWindow | bool | true | El botón de abrir lanza la ficha en una ventana. |
Client | DinaupClientC | null | Cliente, necesario para abrir la ficha del valor. |
Columns | RenderFragment | null | Columnas personalizadas del desplegable. |
ValueTemplate | RenderFragment<dynamic> | null | Plantilla del valor seleccionado. |
IconTemplate | RenderFragment<T> | null | Plantilla del icono por elemento. |
ColumnWidth | string | "" | Ancho de las columnas. |
OnAdd | EventCallback | — | Clic en el botón de añadir. |
OnRemove | EventCallback<T> | — | Clic en limpiar la selección. |
OnOpen | EventCallback<T> | — | Clic en abrir la ficha del valor. |
Acepta además atributos extra que se pasan tal cual al elemento raíz.
DnzRowSelector
Selector que busca contra un informe remoto mientras escribes. Para fichas que viven en el servidor (clientes, productos) y son demasiadas para tener en memoria.
<DnzRowSelector Client=@_client ReportId="guid-informe-clientes" @bind-SelectedRow=@_clienteSel Label="Cliente" />Parámetros
| Parámetro | Tipo | Por defecto | Qué hace |
|---|---|---|---|
Client | DinaupClientC | — | Obligatorio. Cliente del SDK ya inicializado. |
ReportId | string | null | GUID del informe contra el que busca. |
SelectedRow | IDinaupRow | null | Fila seleccionada. Usa @bind-SelectedRow. |
Label | string | null | Etiqueta del campo. |
Icon | string | null | Icono a la izquierda. |
Placeholder | string | null | Texto cuando no hay selección. |
Width | string | "280px" | Ancho del control. |
Style | string | "flex:1" | Estilo CSS extra. |
Class | string | "" | Clases CSS extra. |
IsRequired | bool | false | Marca el campo como obligatorio. |
Disabled | bool | false | Desactiva el control. |
AdminMode | bool | false | Busca en modo administrador. |
AdvancedFilter | List<FilterCondition> | null | Filtros aplicados a la búsqueda. |
OpenInWindow | bool | true | El botón de abrir lanza la ficha en una ventana. |
DefaultID | Guid | Guid.Empty | Preselecciona una fila por su ID al cargar. |
KeyboardShortcut | string | null | Atajo de teclado para abrir el selector. |
OnAdd | EventCallback<Guid> | — | Clic en el botón de añadir. |
OnOpenRecord | EventCallback<IDinaupRow> | — | Clic en abrir la ficha de la fila. |
Acepta además atributos extra que se pasan tal cual al elemento raíz.
Esqueleto de diálogo
Quieres un diálogo con la estructura y los botones de Play: título arriba, contenido en medio, botones al pie con la convención de la casa (cancelar discreto a la izquierda, confirmar destacado a la derecha). DnzDialogLayout te da los tres huecos.
@inject DialogService DialogService
<DnzDialogLayout Title="Editar pedido" Icon="edit">
<BodyContent>
<div class="d-flex flex-column gap-3 p-3">
<RadzenTextBox @bind-Value=@_nombre Placeholder="Nombre" />
</div>
</BodyContent>
<FooterContent>
<div class="d-flex gap-2 justify-content-end">
<RadzenButton Text="Cancelar" Variant="Variant.Text" ButtonStyle="ButtonStyle.Danger" Click=@CancelarAsync />
<RadzenButton Text="Guardar" ButtonStyle="ButtonStyle.Success" Click=@GuardarAsync IsBusy=@_guardando />
</div>
</FooterContent>
</DnzDialogLayout>
@code {
private string _nombre = "";
private bool _guardando;
private void CancelarAsync() => DialogService.Close();
private async Task GuardarAsync()
{
_guardando = true;
await PersistirAsync();
DialogService.Close(true);
}
}La convención del pie: Cancelar en Danger + Text (discreto), Aceptar en Success sólido. Marca el botón de confirmar con IsBusy=@_guardando mientras procesa: el botón muestra el spinner y bloquea el doble clic.
DnzDialogLayout
Estructura de diálogo con cabecera, cuerpo desplazable y pie. Si omites TitleContent, genera la cabecera con Title + Icon + botón de cerrar; si omites FooterContent, muestra un botón "Cerrar" por defecto.
Parámetros
| Parámetro | Tipo | Por defecto | Qué hace |
|---|---|---|---|
Title | string | null | Título de la cabecera (si no usas TitleContent). |
Icon | string | null | Icono Material de la cabecera. |
TitleContent | RenderFragment | null | Cabecera personalizada completa. |
BodyContent | RenderFragment | null | Contenido del cuerpo (desplazable). |
FooterContent | RenderFragment | null | Pie personalizado (botones de acción). |
ContentStyle | string | null | Estilo CSS del cuerpo. |
HeaderStyle | string | null | Estilo CSS de la cabecera. |
Flat | bool | false | Diálogo plano sin degradados ni fondo gris. |
DnzConfirmDialog
Para una acción destructiva (eliminar, vaciar), no montes un diálogo entero: abre la confirmación con el helper estático OpenAsync, que devuelve true si el usuario confirma.
@code {
private async Task EliminarAsync()
{
var ok = await DnzConfirmDialog.OpenAsync(DialogService, "Esta acción no se puede deshacer. ¿Eliminar el pedido?", title: "Eliminar pedido", severity: DnzConfirmSeverity.Danger, okText: "Eliminar");
if (ok == false) return;
await BorrarPedidoAsync();
}
}Firma del helper estático:
Task<bool> DnzConfirmDialog.OpenAsync(DialogService dialogService, string message, string title = "Confirmar", DnzConfirmSeverity severity = DnzConfirmSeverity.Warning, string okText = "Confirmar", string cancelText = "Cancelar")El severity (Info, Warning, Danger, Success) cambia el icono, el color de acento y el estilo del botón de confirmar. Para algo irreversible, usa DnzConfirmSeverity.Danger.
Estados de carga
Mostrar que algo está pasando es parte de la UX. DinaZen tiene tres piezas y cada una resuelve un momento distinto:
DnzLoader— estoy ejecutando una acción (guardar, calcular, llamar a la API). Spinner.DnzSkeleton— la interfaz aún no está lista; muestro su silueta gris en su lugar.DnzDeferredContent— quiero renderizar contenido pesado un poco más tarde, mostrando un esqueleto mientras tanto.
@if (_procesando)
{
<DnzLoader />
}@if (_cargando)
{
<DnzSkeleton Lines="3" />
}<DnzDeferredContent DelayMs="500">
<GraficoPesado Data=@_datos />
</DnzDeferredContent>DnzLoader
Spinner de "estoy procesando". Centrado por defecto; horizontal si lo necesitas en línea.
<DnzLoader />Parámetros
| Parámetro | Tipo | Por defecto | Qué hace |
|---|---|---|---|
Horizontal | bool | false | Variante horizontal en lugar de centrada. |
DnzSkeleton
Silueta gris animada que ocupa el sitio del contenido mientras carga.
<DnzSkeleton Lines="3" Height="1.2rem" />Parámetros
| Parámetro | Tipo | Por defecto | Qué hace |
|---|---|---|---|
Lines | int | 1 | Número de líneas (rectángulos) a mostrar. |
Height | string | "1rem" | Altura de cada línea. |
Radius | string | "0.25rem" | Radio de las esquinas. |
MaxWidth | string | "100%" | Ancho máximo del bloque. |
DnzDeferredContent
Retrasa el render del contenido pesado un instante y muestra un esqueleto mientras tanto. Útil para que las subpáginas pesadas no bloqueen la primera pintura.
<DnzDeferredContent DelayMs="500">
<SeccionPesada />
</DnzDeferredContent>Parámetros
| Parámetro | Tipo | Por defecto | Qué hace |
|---|---|---|---|
DelayMs | int | 500 | Milisegundos antes de mostrar el contenido. |
ChildContent | RenderFragment | — | Contenido que se renderiza tras el retardo. |
LoadingContent | RenderFragment | null | Contenido de carga personalizado (por defecto, un DnzSkeleton). |
Class | string | "" | Clases CSS del contenedor de carga. |
Relacionado
- DinaZen — introducción, instalación y convenciones de la librería.
- Cliente Dinaup — crear el
DinaupClientCque alimenta estas recetas. - SDK .NET — conexión, lectura y escritura de datos.
- Informes de Dinaup Flex — de dónde sale el GUID que pasas a
DnzReportView.