Botones de cuadrícula
Los botones de la barra de herramientas de cuadrícula controlan cómo los usuarios interactúan con los registros en un MainGrid o SubGrid. Los botones se colocan dentro del Buttons fragmento de renderizado y aparecen automáticamente en la barra de herramientas de la cuadrícula.
Categorías de botones
Existen tres categorías de botones de cuadrícula según cómo gestionan las operaciones de registro:
- Botones de diálogo — Abre un formulario en un diálogo para crear o editar registros en línea sin salir de la página.
- Botones de navegación — Navega a una URL de página separada para crear o editar registros.
- Botones de acción — Realizar operaciones como eliminar, vincular o desvincular registros directamente.
Elegir el enfoque adecuado
Elige la forma del botón en función de cuánto contexto necesita el usuario y cuánta nueva situación haya involucrada. Los tres cubos de abajo cubren los casos típicos.
- Diálogo (en línea) — Úsalo
NewRecordGridButton/OpenRecordGridButtoncuando el formulario encaja en un solo diálogo y el usuario se beneficia de permanecer en la página actual (por ejemplo, añadiendo un contacto a un registro de cuenta sin perder las demás ediciones no guardadas de la cuenta). Combina conBehavior="GridActionBehavior.WithGridContext"(el valor predeterminado) para integrar la partida guardada del nuevo registro en el commit transaccional del contexto padre. - Navegar (página completa) — Usar
NavigateNewRecordGridButton/NavigateOpenRecordGridButtoncuando crear o editar necesita una superficie más rica que la que un diálogo puede ofrecer cómodamente: muchos campos, múltiples pestañas, registros relacionados propios, archivos adjuntos o URLs compartibles. La ruta posee su propioRecordContext, por lo que la cuadrícula principal no necesita ser consciente de la complejidad del formulario. - Asistente (diálogo de varios pasos) — Úsalo
NewRecordGridButton FormType="FormType.WizardForm"cuando el formulario tiene suficientes campos para que una pantalla se sienta saturada, pero las entradas son lo bastante interdependientes como para que dividir entre páginas merezca la pena el coste de navegación. Forma común: la página 1 captura la identidad / clasificación, la página 2 captura detalles que dependen de las elecciones de la página 1.
Guardar flujo y modos de comportamiento
Cada botón de cuadrícula basado en diálogo (NewRecordGridButton, OpenRecordGridButton, el par de enlace / desenlace M2M) acepta un Behavior parámetro que controla cuándo se activa la llamada subyacente de Dataverse. Los dos valores se corresponden con secuencias de peticiones materialmente diferentes:
Comportamiento = Inmediatamente
El botón de guardar del diálogo emite la solicitud de crear / actualizar / asociar / desasociar directamente a Dataverse mediante ExecuteMultipleAsync, actualiza la cuadrícula y luego cierra el diálogo. El entorno MainContext / RecordContext (si es que existe) no ve el cambio — ya está comprometido.
- El usuario hace clic en guardar en el diálogo.
- El diálogo valida y luego se envía una o más
OrganizationRequests aExecuteMultipleAsynctravés de . - Retornos de servidores; la cuadrícula se refresca; El diálogo se cierra.
Elige esto cuando: el diálogo esté solo (no haya un botón de guardar a nivel de página cercano), o el usuario realmente quiera que cada acción a nivel de fila sea un commit propio. Cada guardado aquí es independiente: la finalización parcial de un flujo de trabajo multifila permanece en el servidor.
Comportamiento = ConContextoDeCuadrícula (por defecto)
El botón de guardar del diálogo activa la solicitud en la cola pendiente de la cuadrícula (_rowsToCreate / _rowsToUpdate en Blazor, el equivalente en React en useGridContext()) y cierra el diálogo. La llamada real de Dataverse no se activa hasta que se hace clic en el botón de guardar de / RecordContextque rodea.MainContext
- El usuario hace clic en Guardar en el diálogo → registro (o actualizar/asociar/disociar) se coloca en cola en la cuadrícula.
- Se cierra el diálogo. El contexto padre de la página cambia a
IsDirty=true; el botón de guardar a nivel de página lo habilita. - El usuario hace clic en el Guardar a nivel de página → cada cambio de cuadrícula en cola + la actualización propia del registro padre + todas las solicitudes pendientes de los demás descendientes se agrupan en un solo
ExecuteMultipleAsync. - Retornos de servidores; la página se actualiza; colas despejadas;
IsDirtyse vuelve a girar.
Elige esto cuando: la página tiene un padre RecordContext con su propio botón de guardar: el usuario espera una semántica de "guardar toda la página", y un commit parcial (el padre guardado, filas hijas no) sería un resultado peor que volver a juntar todo. Por esa razón, es el predeterminado.
Por defecto es WithGridContext
WithGridContextes el predeterminado para todos los botones basados en diálogo — Inmediatamente es opt-in. Si tu cuadrícula está fuera de un contexto padre (una página de listado independiente sin registro encima), la cola no tiene a dónde vaciar y el diálogo vuelve automáticamente a la semántica de Inmediatamente.
NuevoRegistroBotón de la Rejilla
Abre un formulario de diálogo para crear un nuevo registro. Requiere un TForm parámetro de tipo que especifique el componente Razor para renderizar como la forma.
Utilízalo Location para controlar dónde aparece el diálogo: DialogLocation.Center (por defecto) o DialogLocation.Right (panel lateral).
Úsase FormType para elegir entre una forma estándar (FormType.Form) o un asistente de varios pasos (FormType.WizardForm).
Úsalo Behavior para controlar cuándo se crea el registro: GridActionBehavior.Immediately guarda en Dataverse inmediatamente, mientras GridActionBehavior.WithGridContext que (por defecto) pospone la partida hasta que el contexto padre esté comprometido.
{/* Diálogo central con formato estándar */}
<NewRecordGridButton>
<NewContactForm />
</NewRecordGridButton>
{/* Panel lateral con forma estándar */}
<NewRecordGridButton location="panel">
<NewContactForm />
</NewRecordGridButton>
{/* Diálogo central con la forma de mago — los niños son <WizardRecordPage>
elementos (no se necesita prop FormType; el botón detecta automáticamente). */}
<NewRecordGridButton location="center">
<WizardRecordPage>
<TextEdit columnName="firstname" />
<TextEdit columnName="lastname" />
</WizardRecordPage>
<WizardRecordPage>
<MoneyEdit columnName="annualincome" />
</WizardRecordPage>
</NewRecordGridButton>
{/* Guarda inmediatamente en lugar de posponer */}
<NewRecordGridButton behavior="immediately">
<NewContactForm />
</NewRecordGridButton><!-- Diálogo central con formato estándar -->
<NewRecordGridButton TForm="NewContactForm" />
<!-- Panel lateral con forma estándar -->
<NewRecordGridButton TForm="NewContactForm"
Location="DialogLocation.Right" />
<!-- Diálogo central con forma de asistente -->
<NewRecordGridButton TForm="NewContactForm"
Location="DialogLocation.Center"
FormType="FormType.WizardForm" />
<!-- Guarda inmediatamente en lugar de posponer -->
<NewRecordGridButton TForm="NewContactForm"
Behavior="GridActionBehavior.Immediately" />Ejemplo de Formulario Estándar
El TForm parámetro tipo especifica un componente Razor que define la disposición del formulario. Un formulario estándar es simplemente un componente de Razor que contiene componentes del editor. Puede incluir pestañas, secciones o cualquier diseño que necesites.
// EditContactForm.tsx
<TabList>
<Tab value="general">General</Tab>
<Tab value="other">Otros</Tab>
</TabList>
{activeTab === 'general' && (
<>
<TextEdit columnName="firstname" />
<TextEdit columnName="middlename" />
<TextEdit columnName="lastname" />
</>
)}
{activeTab === 'other' && (
<>
<MoneyEdit columnName="annualincome" />
<TextEdit columnName="telephone1" type="tel" />
</>
)}<!-- EditContactForm.razor -->
<FluentTabs Style="width: 100%">
<FluentTab Label="General">
<TextEdit ColumnName="firstname" />
<TextEdit ColumnName="middlename" />
<TextEdit ColumnName="lastname" />
</FluentTab>
<FluentTab Label="Otros">
<MoneyEdit ColumnName="annualincome" />
<TextEdit ColumnName="telephone1"
TextFieldType="TextFieldType.Tel" />
</FluentTab>
</FluentTabs>Ejemplo de Formulario de Asistente
Una forma de asistente divide el proceso de creación en varios pasos. Define cada paso usando WizardRecordPage componentes. Úsalo FormType="FormType.WizardForm" en el botón para activar el modo mago.
// NewContactForm.tsx
<WizardRecordPage>
<TextEdit columnName="firstname" />
<TextEdit columnName="middlename" />
<TextEdit columnName="lastname" />
</WizardRecordPage>
<WizardRecordPage>
<MoneyEdit columnName="annualincome" />
<TextEdit columnName="telephone1" type="tel" />
</WizardRecordPage><!-- NewContactForm.razor -->
<WizardRecordPage>
<TextEdit ColumnName="firstname" />
<TextEdit ColumnName="middlename" />
<TextEdit ColumnName="lastname" />
</WizardRecordPage>
<WizardRecordPage>
<MoneyEdit ColumnName="annualincome" />
<TextEdit ColumnName="telephone1"
TextFieldType="TextFieldType.Tel" />
</WizardRecordPage>Nota
Al usar una forma de asistente, se asigna
FormType="FormType.WizardForm"en elNewRecordGridButton. El asistente muestra la navegación Atrás/Siguiente y valida cada página antes de avanzar.
Validación por página
Cada uno WizardRecordPage se asigna por defecto ForceSuccessfulValidationBeforeSave="true"a: el botón Siguiente del asistente ejecuta los validadores de la página activa antes de avanzar y cancela la transición si algún campo requerido está vacío o no es válido. Configura false páginas que solo contengan campos opcionales para que el usuario pueda saltárselos. El botón Terminar de la última página siempre valida independientemente de esta bandera — el rechazo del creador desde el servidor es la única forma de evitarlo.
<WizardRecordPage>
{/* Campos obligatorios aquí: el usuario no puede avanzar hasta que se llenen */}
<TextEdit columnName="firstname" />
<TextEdit columnName="lastname" />
</WizardRecordPage>
<WizardRecordPage forceSuccessfulValidationBeforeSave={false}>
{/* Campos opcionales — el usuario puede avanzar incluso con errores de validación */}
<MoneyEdit columnName="annualincome" />
</WizardRecordPage><WizardRecordPage>
<!-- Campos obligatorios aquí: el usuario no puede avanzar hasta que se llenen -->
<TextEdit ColumnName="firstname" />
<TextEdit ColumnName="lastname" />
</WizardRecordPage>
<WizardRecordPage ForceSuccessfulValidationBeforeSave="false">
<!-- Campos opcionales — el usuario puede avanzar incluso con errores de validación -->
<MoneyEdit ColumnName="annualincome" />
</WizardRecordPage>Registro compartido entre páginas
Todos los WizardRecordPage componentes dentro de uno NewRecordGridButton comparten el mismo objeto subyacente TableRecord : editar firstname en la página 1 y annualincome en la página 2 termina en una única carga útil de creación al final. Los s por página RecordContextse vinculan a la misma instancia de registro, por lo que la navegación entre pasos preserva las ediciones en curso.
OpenRecordGridButton
Abre un formulario de diálogo para editar el(los) registro(s) seleccionado(s). Por ejemplo NewRecordGridButton, requiere un TForm parámetro de tipo. Cuando se seleccionan varios registros, el formulario muestra campos compartidos y aplica cambios a todos los registros seleccionados.
El botón de edición se activa automáticamente cuando una fila hace doble clic en la cuadrícula. Ponlo AllowNavigateOnRowDoubleClick="false" en la cuadrícula para suprimir el controlador de doble clic.
Por defecto, la columna de nombre principal de la tabla también se muestra como un hipervínculo en cada fila, y al hacer clic en el enlace se activa la misma acción de edición que el doble clic. Configura AllowNavigateOnPrimaryNameClick="false" en la cuadrícula para suprimir el hipervínculo y renderizar la celda del nombre principal como texto plano. El hipervínculo solo aparece cuando se registra un OpenRecordGridButton o, NavigateOpenRecordGridButton por lo que las cuadrículas sin botón de edición no se ven afectadas.
{/* Diálogo de centro (por defecto) */}
<OpenRecordGridButton>
<EditContactForm />
</OpenRecordGridButton>
{/* Panel lateral */}
<OpenRecordGridButton location="panel">
<EditContactForm />
</OpenRecordGridButton>
{/* Guarda inmediatamente */}
<OpenRecordGridButton behavior="immediately">
<EditContactForm />
</OpenRecordGridButton>
{/* Suprimir el hipervínculo del nombre principal (el doble clic en la fila sigue activando la edición) */}
<MainGrid tableName="contact" allowNavigateOnPrimaryNameClick={false}>
<GridButtons>
<OpenRecordGridButton>
<EditContactForm />
</OpenRecordGridButton>
</GridButtons>
</MainGrid>
{/* Suprimir el controlador de doble clic de fila (el hipervínculo de nombre principal sigue funcionando) */}
<MainGrid tableName="contact" allowOpenOnRowDoubleClick={false}>
<GridButtons>
<OpenRecordGridButton>
<EditContactForm />
</OpenRecordGridButton>
</GridButtons>
</MainGrid><!-- Diálogo de centro (por defecto) -->
<OpenRecordGridButton TForm="EditContactForm" />
<!-- Panel lateral -->
<OpenRecordGridButton TForm="EditContactForm"
Location="DialogLocation.Right" />
<!-- Guarda inmediatamente -->
<OpenRecordGridButton TForm="EditContactForm"
Behavior="GridActionBehavior.Immediately" />
<!-- Suprimir el hipervínculo del nombre principal (el doble clic en la fila sigue activando la edición) -->
<MainGrid TableName="contact"
AllowNavigateOnPrimaryNameClick="false">
<Buttons>
<OpenRecordGridButton TForm="EditContactForm" />
</Buttons>
</MainGrid>
<!-- Suprimir el controlador de doble clic de fila (el hipervínculo de nombre principal sigue funcionando) -->
<MainGrid TableName="contact"
AllowNavigateOnRowDoubleClick="false">
<Buttons>
<OpenRecordGridButton TForm="EditContactForm" />
</Buttons>
</MainGrid>NavegarNuevoRegistroBotón de la Rejilla
Navega a una URL para crear un nuevo registro. Configura el Url parámetro en la página de destino. Cuando se usa en un SubGrid, el contexto de relación del registro padre se añade automáticamente como parámetros de cadena de consulta.
Utiliza el OnClick callback para establecer dinámicamente la URL según el contexto de la cuadrícula. Esto es útil para cuadrículas multi-tabla donde la URL depende de la tabla de la vista seleccionada.
{/* URL estática */}
<NavigateNewRecordGridButton url="/contacts/new" />
{/* URL dinámica basada en la vista seleccionada */}
<NavigateNewRecordGridButton
url="/contacts/new"
onClick={(ctx) => {
switch (ctx.gridContext.selectedView?.tableName) {
case 'contact': ctx.url = '/contacts/new'; break;
case 'account': ctx.url = '/accounts/new'; break;
default: throw new Error('Tabla desconocida');
}
}}
/><!-- URL estática -->
<NavigateNewRecordGridButton Url="/contacts/new" />
<!-- URL dinámica basada en la vista seleccionada -->
<NavigateNewRecordGridButton OnClick="OnNewClick" />
@code {
private async Task OnNewClick(NavigateGridButtonContext ctx)
{
ctx.Url = ctx.GridContext.SelectedView.TableName switch
{
"contact" => "/contacts/new",
"account" => "/accounts/new",
_ => throw new Exception("Tabla desconocida"),
};
}
}NavegarAbrirRegistroBotón de la Cuadrícula
Navega a una URL para editar el registro seleccionado. El Url parámetro es compatible {0} como un marcador de posición para el ID del registro seleccionado.
{/* Construye la URL por registro mediante urlFor */}
<NavigateOpenRecordGridButton
urlFor={(record) => `/contacts/edit?contactId=${record.id}`}
/>
{/* URL dinámica basada en la vista seleccionada */}
<NavigateOpenRecordGridButton
urlFor={(record, ctx) => {
switch (ctx.selectedView?.tableName) {
case 'contact': return `/contacts/edit?contactId=${record.id}`;
case 'account': return `/accounts/edit?accountId=${record.id}`;
default: throw new Error('Tabla desconocida');
}
}}
/><!-- {0} se reemplaza por el ID del registro seleccionado -->
<NavigateOpenRecordGridButton Url="/contacts/edit?contactId={0}" />
<!-- URL dinámica -->
<NavigateOpenRecordGridButton OnClick="OnEditClick" />
@code {
private async Task OnEditClick(NavigateGridButtonContext ctx)
{
ctx.Url = ctx.GridContext.SelectedView.TableName switch
{
"contact" => "/contacts/edit?contactId={0}",
"account" => "/accounts/edit?accountId={0}",
_ => throw new Exception("Tabla desconocida"),
};
}
}NavegarRegistroBotón de la Rejilla
Un botón de navegación de propósito general con una etiqueta, icono y URL personalizados. Usa esto para acciones de navegación personalizadas que no encajen con el nuevo patrón o edición.
<NavigateRecordGridButton
title="Ver detalles"
url="/records/details?id={0}"
buttonEnabledBehavior={GridButtonBehavior.OnlyOneSelected}
/><NavigateRecordGridButton Title="Ver detalles"
Url="/records/details?id={0}"
ButtonEnabledBehavior="GridButtonBehavior.WhenOneSelected" />BorrarRegistroBotón de la RejillaT
Elimina los registros seleccionados tras pedir confirmación. Se usa Mode para controlar si los registros se eliminan BulkOperationMode.Individually (uno a uno con el progreso) o en un solo lote.
{/* Elimina uno a uno con el progreso */}
<DeleteRecordGridButton mode="individually" />
{/* Eliminar en un solo lote */}
<DeleteRecordGridButton mode="bulk" />
{/* Elimina inmediatamente sin posponer */}
<DeleteRecordGridButton behavior="immediately" /><!-- Elimina uno a uno con el progreso -->
<DeleteRecordGridButton Mode="BulkOperationMode.Individually" />
<!-- Eliminar en un solo lote -->
<DeleteRecordGridButton Mode="BulkOperationMode.Batch" />
<!-- Elimina inmediatamente sin posponer -->
<DeleteRecordGridButton Behavior="GridActionBehavior.Immediately" />LinkExistentingRecordGridButton
Abre un diálogo de búsqueda para encontrar y asociar registros existentes mediante una relación muchos-a-muchos. Solo aplicable en SubGrid relaciones N:N.
<LinkExistingRecordGridButton />
{/* Asocia inmediatamente */}
<LinkExistingRecordGridButton behavior="immediately" /><LinkExistingRecordGridButton />
<!-- Asocia inmediatamente -->
<LinkExistingRecordGridButton Behavior="GridActionBehavior.Immediately" />DesvincularExistenciaRegistroBotón de la Cuadrícula
Desvincula los registros seleccionados de una relación de muchos a muchos tras pedir confirmación. Solo aplicable en SubGrid relaciones N:N.
<UnlinkExistingRecordGridButton />
{/* Desasocia inmediatamente */}
<UnlinkExistingRecordGridButton behavior="immediately" /><UnlinkExistingRecordGridButton />
<!-- Desasocia inmediatamente -->
<UnlinkExistingRecordGridButton Behavior="GridActionBehavior.Immediately" />GridButton
Un botón totalmente personalizado con una OnClick callback que recibe el archivo actual GridContext. Usa esto para implementar acciones personalizadas en la barra de herramientas.
<SubGrid relationshipName="contact_customer_accounts">
<GridButtons>
<NewRecordGridButton>
<NewContactForm />
</NewRecordGridButton>
<OpenRecordGridButton>
<EditContactForm />
</OpenRecordGridButton>
<DeleteRecordGridButton />
{/* Botón personalizado */}
<GridButton
label="Exportación"
icon={<ArrowDownload20Regular />}
enabledBehavior={GridButtonBehavior.OneOrMoreSelected}
onClick={async (ctx) => {
const selectedRecords = ctx.selectedRecords;
// Lógica personalizada — exportar, imprimir, enviar correos, etc.
}}
/>
</GridButtons>
</SubGrid><SubGrid RelationshipName="contact_customer_accounts">
<Buttons>
<NewRecordGridButton TForm="NewContactForm" />
<OpenRecordGridButton TForm="EditContactForm" />
<DeleteRecordGridButton />
<!-- Botón personalizado -->
<GridButton Label="Exportación"
Icon="@(new Icons.Regular.Size20.ArrowDownload())"
IsButtonEnabled="DefaultGridButtonBehavior.GetBehavior(GridButtonBehavior.WhenOneOrMoreSelected)"
OnClick="OnExportClick" />
</Buttons>
</SubGrid>
@code {
private async Task OnExportClick(GridContext context)
{
var selectedRecords = context.SelectedRecords;
// Lógica personalizada — exportar, imprimir, enviar correos, etc.
}
}Parámetros comunes
Behavior— Controla si la operación se ejecuta inmediatamente (GridActionBehavior.Immediately) o se diferió hasta que el contexto padre guarde (GridActionBehavior.WithGridContext).Mode— Para los botones de eliminar/enlazar/desvincular, controla si las operaciones masivas se ejecutan individualmente con retroalimentación de progreso o en una sola solicitud por lote.IsButtonEnabled/IsButtonVisible— Predica que controla el estado del botón en función de la selección de fila actual.
GridButton Clase
Parámetros
Nombre | Tipo | Default | Descripción |
|---|---|---|---|
Appearance | Appearance? | Stealth | Apariencia visual del botón de la barra de herramientas. Valores predeterminados de Appearance.Stealth Así que el botón se lee como transparente en reposo y solo pinta un fondo al pasar el cursor — coincidiendo con los botones de Actualizar y Configuración de la cuadrícula. El CSS con alcance de la cuadrícula (Appearance.Accent para una llamada a la acción primaria). |
Enabled | bool? | True | Anula el estado habilitado del botón independientemente del GridButton.IsButtonEnabled resultado del predicado. |
Icon | Icon? | Un icono opcional mostrado en el botón. | |
IsButtonEnabled | Func<IEnumerable<GridRowContext>, bool> | Un predicado evaluado frente a la selección de fila actual para determinar si el botón está activado. | |
IsButtonVisible | Func<IEnumerable<GridRowContext>, bool> | Un predicado evaluado frente a la selección de fila actual para determinar si el botón es visible. | |
IsOpenRecordButton | bool | False | Especifica que este es el botón 'Editar' para la cuadrícula. Solo un botón debería tener esta propiedad configurada como 'verdadero' en una cuadrícula. El manejador de eventos de este botón se llama cuando una fila se hace 'doble clic' en la cuadrícula. |
Label | string? | La etiqueta de texto mostrada en el botón. | |
Tooltip | string? | Una descripción emergente opcional se muestra cuando el usuario se queda suspendido sobre el botón. |
AppearanceAppearance.Stealth Así que el botón se lee como transparente en reposo y solo pinta un fondo al pasar el cursor — coincidiendo con los botones de Actualizar y Configuración de la cuadrícula. El CSS con alcance de la cuadrícula (Appearance.Accent para una llamada a la acción primaria).EnabledGridButton.IsButtonEnabled resultado del predicado.IconIsButtonEnabledIsButtonVisibleIsOpenRecordButtonLabelTooltipEventos
Nombre | Tipo | Descripción |
|---|---|---|
OnClick | EventCallback<GridContext> | Dispara cuando se pulsa el botón, proporcionando la corriente Components.GridContext al manejador. |
OnClickComponents.GridContext al manejador.