Mientras continuamos ampliando las capacidades de la interfaz de usuario de ASP.NET Core Blazor de XAF, puede ofrecer experiencias de usuario intuitivas para la plataforma ASP.NET Core Blazor. Este tutorial documenta cómo crear una aplicación para almacenar contactos y otros objetos relacionados utilizando la interfaz de usuario de ASP.NET Core Blazor de XAF.
Si es nuevo en XAF, asegúrese de revisar nuestra página de productos XAF para obtener información importante sobre nuestro galardonado marco de aplicación.
Antes de comenzar el tutorial, lea esta sección y asegúrese de que se cumplen las siguientes condiciones:
- Visual Studio 2022 v17.0+ (con la carga de trabajo de desarrollo web y ASP.NET) está instalado en el equipo. Tiene experiencia básica en el desarrollo de .NET Framework en este IDE.
- .NET 6 SDK está instalado en el equipo.
- Una versión de prueba gratuita de 30 días o una versión con licencia de DevExpress Universal Subscription está instalada en su equipo.
- Tiene conocimientos básicos de los conceptos de asignación relacional de objetos (ORM) y de DevExpress XPO.
- Cualquier RDBMS compatible con la herramienta XPO ORM (consulte Sistemas de bases de datos compatibles con XPO) se instala y se puede acceder a él desde el equipo para almacenar los datos de la aplicación (se recomienda una instancia de LocalDB o SQL Server Express).
- Está familiarizado con la arquitectura de aplicaciones XAF.
Este tutorial está organizado de la siguiente manera:
- Diseño de Modelo de Negocio
En esta sección se explica cómo implementar clases que definen la base del modelo de negocio de la aplicación y su estructura de base de datos asociada.
- Amplíe la funcionalidad
En esta sección se explica cómo ampliar la interfaz de usuario generada automáticamente de XAF con comandos personalizados.
- Personalización de la interfaz de usuario
En esta sección se explica cómo personalizar la interfaz de usuario de la aplicación Core Blazor ASP.NET generada automáticamente por XAF.
Este tutorial utiliza SQL Server de Microsoft como su sistema de administración de bases de datos (DBMS) de destino. Como ya sabrá, XAF admite múltiples sistemas de administración de bases de datos (consulte la lista aquí). Si desea utilizar un DBMS diferente, asegúrese de especificar la cadena de conexión adecuada.
Las aplicaciones XAF crean una base de datos con un nombre que coincide con el nombre utilizado para la propia solución. Para cambiar los nombres, edite la cadena de conexión en el archivo de configuración de la aplicación (appsettings.json).
Para volver a crear la base de datos, suéltela del servidor de bases de datos o elimine el archivo. La aplicación XAF volverá a crear la base de datos en el siguiente inicio.
En esta sección se explica cómo diseñar un modelo de negocio (base de datos) para una aplicación creada con eXpressApp Framework.
Aprenderá a completar las siguientes tareas:
- Crear clases de negocio asignadas a tablas de base de datos
- Especificar relaciones entre clases
- Implementar propiedades dependientes
- Agregar validación de valor de propiedad
Puede diseñar un modelo de negocio de cualquiera de las siguientes maneras:
-
Usar la biblioteca de clases empresariales de DevExpress
La biblioteca de clases empresariales incluye clases empresariales de uso frecuente, como Persona, Evento, Tarea, etc. Puede utilizar una clase de esta biblioteca tal cual, o heredarla y ampliarla.
-
Crear clases personalizadas
Si utiliza XPO, herede los objetos de negocio de las clases persistentes base.
SUGERENCIA: Para obtener información sobre cómo crear una aplicación basada en una base de datos existente, consulte el tema siguiente: Cómo: Generar clases empresariales de XPO para tablas de datos existentes.
Una vez que complete el tutorial, su aplicación básica ASP.NET Core Blazor CRUD se verá como se muestra en la imagen a continuación.
Esta lección crea una nueva solución XAF y le guía a través del Asistente para soluciones XAF. En el asistente, hará lo siguiente:
- Agregue un proyecto de interfaz de usuario de Blazor a la solución.
- Seleccione una herramienta ORM para usarla en la administración de datos.
- Active la autenticación de usuario.
- Revise los módulos integrados disponibles y habilite el módulo de validación.
Al final de esta lección, puede ejecutar la aplicación por primera vez.
-
En el menú principal de Visual Studio, seleccione Archivo | Nuevo | Proyecto... para invocar el cuadro de diálogo Crear un nuevo proyecto.
-
Seleccione DevExpress v22.1 XAF Template Gallery y haga clic en Siguiente. Especifique el nombre del proyecto ("MiSolución") y haga clic en Crear.
- En la ventana Galería de plantillas invocada, cambie a la sección .NET Core. Seleccione Asistente para soluciones XAF (.NET Core) y haga clic en Ejecutar asistente.
- En la primera página del Asistente para soluciones, puede seleccionar la plataforma de destino. Dado que este tutorial solo muestra la interfaz de usuario de Blazor, seleccione la opción Web (ASP.NET Core Blazor) y haga clic en Siguiente.
- Elija la biblioteca ORM de objetos persistentes de DevExpress eXpress.
- Elija el tipo de autenticación para su aplicación. En este tutorial, usamos Standard. Haga clic en Siguiente.
- Select the ready-to-use XAF modules you want to add to your application. This tutorial requires the Validation module. Click Finish.
`` The solution contains the following projects:
- MySolution.Blazor.Server - the ASP.NET Core Blazor application project that automatically generates the ASP.NET Core Blazor CRUD user interface. This project depends on the MySolution.Module.
- MySolution.Module - the module project that contains platform-independent code.
Refer to the Application Solution Structure topic for information on the XAF solution structure.
-
Ahora puede ejecutar la aplicación. Haga clic en Iniciar depuración o presione F5.
Las siguientes imágenes muestran la aplicación ASP.NET Core Blazor. Inicie sesión como "Admin" y use una cadena vacía como contraseña.
El asistente intenta buscar la instancia de Microsoft SQL Server instalada (LocalDB o Express) y establece la cadena de conexión en consecuencia.
Consulte el tema Conectar una aplicación XAF a un proveedor de bases de datos para obtener más información sobre cómo conectarse a diferentes sistemas de bases de datos.
En esta lección, aprenderá a implementar clases de negocio para su aplicación mediante la Biblioteca de clases empresariales. Esta biblioteca contiene las clases de negocios listas para usar más típicas. Implementará una clase Contact personalizada derivando de la clase Person disponible en esta biblioteca e implementará varias propiedades adicionales. También aprenderá los conceptos básicos de la construcción automática de la interfaz de usuario basada en datos.
-
Haga clic con el botón secundario en la carpeta Business Objects del proyecto MySolution.Module y elija Agregar elemento | Clase..., especifique Contacto.cs como el nuevo nombre de clase y haga clic en Agregar.
-
Reemplace la declaración de clase generada por el código siguiente.
using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl; using DevExpress.Persistent.Validation; using DevExpress.Xpo; using System; namespace MySolution.Module.BusinessObjects { [DefaultClassOptions] public class Contact : Person { public Contact(Session session) : base(session) { } private string webPageAddress; public string WebPageAddress { get { return webPageAddress; } set { SetPropertyValue(nameof(WebPageAddress), ref webPageAddress, value); } } private string nickName; public string NickName { get { return nickName; } set { SetPropertyValue(nameof(NickName), ref nickName, value); } } private string spouseName; public string SpouseName { get { return spouseName; } set { SetPropertyValue(nameof(SpouseName), ref spouseName, value); } } private TitleOfCourtesy titleOfCourtesy; public TitleOfCourtesy TitleOfCourtesy { get { return titleOfCourtesy; } set { SetPropertyValue(nameof(TitleOfCourtesy), ref titleOfCourtesy, value); } } private DateTime anniversary; public DateTime Anniversary { get { return anniversary; } set { SetPropertyValue(nameof(Anniversary), ref anniversary, value); } } private string notes; [Size(4096)] public string Notes { get { return notes; } set { SetPropertyValue(nameof(Notes), ref notes, value); } } } public enum TitleOfCourtesy { Dr, Miss, Mr, Mrs, Ms }; }
-
Ejecute la aplicación.
XAF genera una interfaz de usuario basada en las estructuras de datos especificadas:
-
una vista de lista
La vista de lista muestra la lista de contactos. Si los usuarios hacen clic en el botón Nuevo o en un registro existente, la aplicación muestra un formulario de detalle (Vista detallada) lleno de editores para cada campo de datos.
-
Normalmente, las clases de negocio no dependen de la interfaz de usuario de la aplicación y deben implementarse en un proyecto de módulo independiente de la plataforma. Los objetos de negocio se pueden compartir con otras aplicaciones XAF o no XAF.
En esta lección, derivamos el objeto Contact de la clase Person. La clase Persona es una de las clases de Biblioteca de clase Business. Esta clase ya contiene campos específicos para entidades del tipo Persona: nombre, apellido, fecha de nacimiento, etc.
La clase Person (y el resto de la biblioteca de clases Business) deriva de BaseObject. La clase BaseObject deriva de DevExpress.Xpo.XPCustomObject, una de las clases base de XPO. Esto significa que el objeto de negocio Contact es un objeto persistente.
XPO requiere que implemente colocadores de propiedades y un constructor parametrizado de la siguiente manera:
[DefaultClassOptions]
public class Contact : Person {
public Contact(Session session) : base(session) { }
private string webPageAddress;
public string WebPageAddress {
get { return webPageAddress; }
set { SetPropertyValue(nameof(WebPageAddress), ref webPageAddress, value); }
}
// ...
}
Consulte el siguiente tema de ayuda para obtener más información: Creación de un objeto persistente.
Para obtener información general sobre el concepto de clase empresarial, consulte el tema siguiente: Clases empresariales frente a tablas de base de datos.
NOTA
CodeRush incluye una serie de plantillas de código que ayudan a generar clases de negocio o sus partes con unas pocas pulsaciones de teclas. Para obtener información sobre las plantillas de código para objetos persistentes de eXpress, consulte el siguiente tema de ayuda: Plantillas XPO y XAF.
En este tutorial, la clase de objetos de negocio se decora con el atributo DefaultClassOptionsAttribute. Este atributo significa que las siguientes capacidades están disponibles para la clase empresarial Contact.
- El elemento Contacto se agrega al control de navegación de la página principal. Los usuarios pueden hacer clic en este elemento para acceder a la vista de lista asociada.
- Los objetos de contacto se pueden usar como origen de datos para generar informes (vea Crear un informe en Visual Studio).
Para aplicar cada una de estas opciones por separado, utilice los atributos NavigationItemAttribute y VisibleInReportsAttribute.
XAF genera los editores adecuados para los campos de datos en la vista de lista y la vista de detalle. Por ejemplo, se genera un selector de fecha para los valores de fecha y hora, se crea un editor de cuadros combinados para Título de cortesía (un enumerador).
XAF transforma los subtítulos de camel-case a cadenas separadas por espacios, se actualizan los títulos de los formularios, etc.
Puede utilizar las funciones de cuadrícula en una vista de lista en tiempo de ejecución: reorganizar columnas y ordenar y filtrar datos:
NOTA: Antes de continuar, tómese un momento para revisar la lección Heredar de la clase de biblioteca de clase empresarial (XPO).
- Abra el archivo Updater.cs ubicado en la carpeta Actualización de base de datos del proyecto MySolution.Module. Agregue el código siguiente al método ModuleUpdater.UpdateDatabaseAfterUpdateSchema.
using MySolution.Module.BusinessObjects; //... public class Updater : DevExpress.ExpressApp.Updating.ModuleUpdater { //... public override void UpdateDatabaseAfterUpdateSchema() { base.UpdateDatabaseAfterUpdateSchema(); Contact contactMary = ObjectSpace.FirstOrDefault<Contact>(contact => contact.FirstName == "Mary" && contact.LastName == "Tellitson"); if (contactMary == null) { contactMary = ObjectSpace.CreateObject<Contact>(); contactMary.FirstName = "Mary"; contactMary.LastName = "Tellitson"; contactMary.Email = "[email protected]"; contactMary.Birthday = new DateTime(1980, 11, 27); } //... ObjectSpace.CommitChanges(); } }
- Ejecute la aplicación. Seleccione el elemento Contacto en el control de navegación. Observe que el nuevo contacto, "Mary Tellitson", aparece en la lista de la derecha.
En el paso 1, agregue un código que comprueba si la lista de contactos contiene una entrada que coincide con el nombre "Mary Tellitson". Si dicho contacto no existe, el código lo crea y lo agrega a la base de datos.
Una aplicación XAF comprueba la compatibilidad de versiones de aplicaciones y bases de datos en cada inicio. Se realizan las siguientes comprobaciones:
- La base de datos existe.
- Todas las tablas necesarias existen.
- Todas las columnas obligatorias existen.
El evento XafApplication.DatabaseVersionMismatch se produce si se produce un error en alguna de estas comprobaciones.
La aplicación ASP.NET Core Blazor controla este evento en una plantilla de solución. Cuando la aplicación se ejecuta en modo de depuración, este controlador de eventos utiliza el actualizador de base de datos integrado para actualizar la base de datos de la aplicación. Después de actualizar el esquema de base de datos, se llama al método ModuleUpdater.UpdateDatabaseAfterUpdateSchema. En este método, puede guardar los objetos de negocio necesarios en la base de datos.
Como puede ver en el código anterior, XAF utiliza un objeto Object Space para manipular objetos persistentes (consulte Crear, leer, actualizar y eliminar datos).
Esta lección explica los siguientes conceptos:
- Cómo implementar clases de negocio desde cero
- Cómo implementar referencias de objetos a clases existentes
- Cómo XAF genera la interfaz de usuario para los objetos a los que se hace referencia
NOTA Antes de continuar, tómese un momento para revisar la lección anterior: Heredar de la clase de biblioteca de clase empresarial (XPO).
-
Agregue las siguientes clases persistentes Department y Position al archivo Contact.cs.
namespace MySolution.Module.BusinessObjects { // ... [DefaultClassOptions] [System.ComponentModel.DefaultProperty(nameof(Title))] public class Department : BaseObject { public Department(Session session) : base(session) { } private string title; public string Title { get { return title; } set { SetPropertyValue(nameof(Title), ref title, value); } } private string office; public string Office { get { return office; } set { SetPropertyValue(nameof(Office), ref office, value); } } } [DefaultClassOptions] [System.ComponentModel.DefaultProperty(nameof(Title))] public class Position : BaseObject { public Position(Session session) : base(session) { } private string title; public string Title { get { return title; } set { SetPropertyValue(nameof(Title), ref title, value); } } } }
-
Agregue las propiedades Department y Position a la clase Contact:
[DefaultClassOptions] public class Contact : Person { //... private Department department; public Department Department { get {return department;} set {SetPropertyValue(nameof(Department), ref department, value);} } private Position position; public Position Position { get {return position;} set {SetPropertyValue(nameof(Position), ref position, value);} } //... }
La clase Contact ahora expone las propiedades de referencia Position y Department.
-
Ejecute la aplicación.
Después de ejecutar la aplicación, puede ver que el control de navegación muestra dos elementos nuevos: Departamento y Posición. Puede hacer clic en los nuevos elementos para acceder a las listas de departamentos y puestos.
- Formulario de detalle del departamento:
- Lista de departamentos:
En la vista Detalles de contacto, XAF crea editores de búsqueda para Departamento y Puesto. Estos editores utilizan un tipo especial de vista: la vista de lista de búsqueda. Normalmente, esta vista incluye una sola columna que muestra los valores de la propiedad predeterminada de la clase. Consulte información adicional acerca de las propiedades predeterminadas más adelante en este tema.
Los usuarios pueden seleccionar valores de Departamento o Posición de las listas desplegables. Tenga en cuenta que los editores de búsqueda admiten el filtrado incremental:
Las clases Position y Department están decoradas con el atributo DefaultProperty. Este atributo especifica la propiedad predeterminada de la clase. Puede especificar la propiedad más descriptiva de la clase en el atributo DefaultProperty y, a continuación, sus valores se mostrarán en lo siguiente:
- Leyendas de formulario de detalle
- La columna situada más a la izquierda de una vista de lista
- Vistas de lista de búsqueda
Consulte el tema Anotaciones de datos en el modelo de datos para obtener más información.
En esta lección se explica cómo crear una relación de varios a varios entre objetos de negocio y cómo XAF genera la interfaz de usuario para dichas relaciones.
NOTA Antes de continuar, tómese un momento para revisar la lección anterior: Heredar de la clase de biblioteca de clase empresarial (XPO).
-
Haga clic con el botón secundario en la carpeta Business Objects del proyecto MySolution.Module y elija Agregar | Clase.... Cambie el nombre del archivo a Tarea.cs y haga clic en Agregar. Reemplace el contenido del nuevo archivo con el código siguiente:
using DevExpress.ExpressApp.Model; using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl; using DevExpress.Xpo; namespace MySolution.Module.BusinessObjects { [DefaultClassOptions] [ModelDefault("Caption", "Task")] public class DemoTask : Task { public DemoTask(Session session) : base(session) { } [Association("Contact-DemoTask")] public XPCollection<Contact> Contacts { get { return GetCollection<Contact>(nameof(Contacts)); } } } }
-
Agregue la propiedad Tasks en la implementación de la clase Contact.
[DefaultClassOptions] public class Contact : Person { //... [Association("Contact-DemoTask")] public XPCollection<DemoTask> Tasks { get { return GetCollection<DemoTask>(nameof(Tasks)); } } }
-
Ejecute la aplicación.
En la vista Detalles de contacto, la aplicación muestra los siguientes elementos:
- Una lista de tareas asignadas;
- El botón Nuevo - permite a los usuarios agregar una nueva tarea asignada;
- El botón Vincular: permite a los usuarios asignar al contacto actual una tarea existente.
You can find the same UI in the Tasks detail view.
En la clase DemoTask, AssociationAttribute se aplica a la propiedad Contacts del tipo XPCollection. Esta propiedad representa una colección de contactos asociados. XPO utiliza el atributo Association para establecer una relación entre objetos. La implementación del getter de propiedades Contacts (el método GetCollection) se utiliza para devolver una colección.
[Association("Contact-DemoTask")]
public XPCollection<Contact> Contacts {
get {
return GetCollection<Contact>(nameof(Contacts));
}
}
En la clase Contact, la propiedad Tasks es la segunda parte de la relación Contact-DemoTask. Tenga en cuenta que el atributo Association también debe aplicarse a esta propiedad.
[DefaultClassOptions]
public class Contact : Person {
//...
[Association("Contact-DemoTask")]
public XPCollection<DemoTask> Tasks {
get {
return GetCollection<DemoTask>(nameof(Tasks));
}
}
}
NOTA No modifique la declaración de propiedad XPCollection demostrada anteriormente. Si manipula la colección o introduce cualquier configuración adicional dentro de la declaración, puede provocar un comportamiento impredecible.
Después de ejecutar la aplicación, XPO generará las tablas y relaciones intermedias.
La clase DemoTask está decorada con el atributo ModelDefaultAttribute. Los parámetros de atributo especifican que la propiedad Caption de BOModel | El nodo DemoTask se establece en "Tarea".
Puede aplicar el atributo ModelDefault a una clase de negocio o a su miembro para cambiar cualquier propiedad de la lista de materiales del modelo de aplicación | o BOModel | | Miembros Propios | nodo.
En esta lección se explica cómo crear una relación de uno a varios entre objetos de negocio y cómo XAF genera la interfaz de usuario para dicha relación.
NOTA Antes de continuar, tómese un momento para repasar las lecciones anteriores:
- Heredar de la clase de biblioteca de clase empresarial (XPO)
- Implementar clases empresariales personalizadas y propiedades de referencia (XPO)
- Establecer una relación de varios a varios (XPO)
-
Para implementar la parte "One" de la relación Departamento-Contactos, decore la propiedad Department de la clase Contact con AssociationAttribute.
[DefaultClassOptions] public class Contact : Person { //... private Department department; [Association("Department-Contacts")] public Department Department { get {return department;} set {SetPropertyValue(nameof(Department), ref department, value);} } //... }
Consulte el siguiente tema de ayuda para obtener información sobre el atributo Asociación: Establecer una relación de varios a varios (XPO).
-
Para implementar la parte "Muchos" de la relación Departamento-Contactos, agregue la propiedad Contacts a la clase Department y decore esta propiedad con el atributo Association.
public class Department : BaseObject { //... [Association("Department-Contacts")] public XPCollection<Contact> Contacts { get { return GetCollection<Contact>(nameof(Contacts)); } } }
-
Ejecute la aplicación.
Abra la vista de detalles del departamento. Puede ver el grupo Contactos. Para agregar objetos a la colección Contactos, utilice el botón Nuevo o Vínculo de esta ficha. El botón Vínculo permite a los usuarios agregar referencias a objetos de contacto existentes.
To remove a reference to an object from this collection, use the Unlink button.
TIP: Si crea un nuevo departamento y, a continuación, crea un nuevo contacto en la colección Contactos, el departamento asociado no es visible inmediatamente en la vista detallada del contacto recién creado. El vínculo entre estos objetos se agrega más adelante al guardar el contacto. Para cambiar este comportamiento, utilice la propiedad XafApplication.LinkNewObjectToParentImmediately .
true
. Cuando el valor de la propiedad es , la aplicación crea un vínculo y lo guarda inmediatamente después de hacer clic en Nuevo.``
En esta lección se explica cómo inicializar propiedades en objetos de negocio recién creados.
Para ello, agregará la propiedad Priority a la clase DemoTask creada en la lección Set a Many-to-Many Relationship (XPO). A continuación, reemplazará el método AfterConstruction para inicializar la nueva propiedad.
NOTA Antes de continuar, tómese un momento para repasar las lecciones anteriores:
-
Agregue la propiedad Priority a la clase DemoTask y declare la enumeración Priority, como se muestra a continuación:
public class DemoTask : Task { // ... private Priority priority; public Priority Priority { get { return priority; } set { SetPropertyValue(nameof(Priority), ref priority, value); } } //... } public enum Priority { Low, Normal, High }
-
Para inicializar la propiedad Priority recién agregada cuando se crea un objeto DemoTask, invalide el método AfterConstruction, como se muestra a continuación:
[DefaultClassOptions] [ModelDefault("Caption", "Task")] public class DemoTask : Task { //... public override void AfterConstruction() { base.AfterConstruction(); Priority = Priority.Normal; } //... }
-
Ejecute la aplicación.
Cree un nuevo objeto DemoTask. En la vista Detalles de la tarea, la propiedad Priority se establece en , como se indica en el código anterior.
Priority.Normal
Tenga en cuenta que XAF genera un cuadro combinado para la propiedad Priority. Los elementos del cuadro combinado son los valores de enumeración declarados en el paso 2.
El método AfterConstruction se ejecuta cuando se crea un nuevo objeto de negocio. En este tutorial, reemplazará este método para establecer la propiedad Priority cuando se crea un nuevo objeto DemoTask.Priority.Normal
En esta lección se explica cómo implementar propiedades cuyos valores pueden depender de otras propiedades.
Agregará una nueva propiedad Manager a la clase Contact. El editor de esta propiedad mostrará una lista de los administradores que trabajan en el mismo departamento.
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
-
Agregue una nueva propiedad Manager del tipo Contact a la clase Contact.
[DefaultClassOptions] public class Contact : Person { //... private Contact manager; public Contact Manager { get { return manager; } set { SetPropertyValue(nameof(Manager), ref manager, value); } } //... }
-
Aplique los atributos DataSourceProperty y DataSourceCriteria a la propiedad recién agregada.
[DefaultClassOptions] public class Contact : Person { //... [DataSourceProperty("Department.Contacts", DataSourcePropertyIsNullMode.SelectAll)] [DataSourceCriteria("Position.Title = 'Manager' AND Oid != '@This.Oid'")] public Contact Manager { // ... } // ... }
-
Ejecute la aplicación.
Agregue los siguientes objetos:
- un objeto Department (por ejemplo, "Developer Department")
- varios objetos Contact con la propiedad Department establecida en "Developer Department"
- varios objetos Position (por ejemplo, "Manager", "Developer").
Para los contactos recién agregados, establezca la propiedad Position en:
- "Manager" (para varios objetos de contacto);
- "Desarrollador" (para otros objetos de contacto).
Cree un nuevo objeto Contact. En la Vista de detalles de contacto, especifique la propiedad Department y expanda el editor de búsquedas del administrador. Tenga en cuenta lo siguiente:
- La propiedad Department de los objetos enumerados es la misma que la especificada anteriormente.
- La propiedad Position se establece en "Manager" para cada uno de los objetos enumerados.
Puede utilizar diseñadores XAF integrados para implementar el mismo comportamiento sin código. Para obtener más información, consulte la siguiente lección: Filtrar origen de datos para un editor de búsquedas.
El atributo DataSourceProperty acepta dos parámetros. El primero especifica la ruta a la lista de búsqueda. El segundo parámetro es opcional. Especifica cómo se rellenan los elementos de búsqueda si la aplicación no pudo encontrar ningún elemento de la ruta de acceso.
En este tutorial, el segundo parámetro se establece en SelectAll. También puede establecer los valores SelectNothing o CustomCriteria. En este último caso, se requiere un tercer parámetro para especificar los criterios.
Con el atributo DataSourceCriteria aplicado, el editor de búsquedas del Administrador contiene objetos Contact que satisfacen los criterios especificados en el parámetro attribute.
En esta lección se explica cómo establecer reglas de validación para las clases empresariales y sus propiedades. XAF aplica estas reglas cuando un usuario ejecuta la operación especificada (por ejemplo, guarda un objeto editado).
En esta lección creará una regla que requiere que la propiedad Position.Title no esté vacía. La aplicación aplicará la regla cuando un usuario guarde un objeto Position.
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
NOTA Para usar la funcionalidad de validación de XAF, instale el paquete NuGet y registre el módulo de validación en el proyecto.
DevExpress.ExpressApp.Validation.Blazor
El asistente para proyectos agrega este paquete a todas las aplicaciones nuevas con las opciones de seguridad habilitadas.
-
Aplique el atributo RuleRequiredFieldAttribute a la propiedad Title de la clase Position. Como parámetro, especifique el contexto que desencadena la regla (por ejemplo, ):
DefaultContexts.Save
using DevExpress.Persistent.Validation; //... [DefaultClassOptions] [System.ComponentModel.DefaultProperty(nameof(Title))] public class Position : BaseObject { //... private string title; [RuleRequiredField(DefaultContexts.Save)] public string Title { get { return title; } set { SetPropertyValue(nameof(Title), ref title, value); } } }
-
Ejecute la aplicación.
Haga clic en el botón Nuevo para crear un nuevo objeto Posición. Deje vacía la propiedad Title y haga clic en Guardar. Se muestra el mensaje de error:
El atributo RuleRequiredField define una regla de validación que garantiza que la propiedad Position.Title tiene un valor cuando se guarda el objeto Position.
El Sistema de Validación ofrece una serie de reglas y contextos. Para obtener más información, consulte el tema Reglas de validación. El modelo de aplicación almacena todas las reglas para que un administrador pueda agregar y editar reglas y contextos con el Editor de modelos (consulte el tema Implementar validación de valor de propiedad en el tema Modelo de aplicación).
En esta lección se explica cómo filtrar los datos mostrados en un editor de búsquedas. Este editor aparece en una vista de detalle para las propiedades de referencia y contiene una lista de objetos de otra clase relacionada.
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
-
Especifique una relación de varios a varios entre las clases y. Para obtener más información, consulte el tema siguiente: Establecer una relación de varios a varios (XPO).
Position``Department
[DefaultClassOptions] [System.ComponentModel.DefaultProperty(nameof(Title))] public class Department : BaseObject { //... [Association("Departments-Positions")] public XPCollection<Position> Positions { get { return GetCollection<Position>(nameof(Positions)); } } } [DefaultClassOptions] [System.ComponentModel.DefaultProperty(nameof(Title))] public class Position : BaseObject { //... [Association("Departments-Positions")] public XPCollection<Department> Departments { get { return GetCollection<Department>(nameof(Departments)); } } }
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos. Vaya a la lista de materiales | Nodo MySolution.Module.BusinessObjects. Expanda el nodo secundario Contactar y seleccione OwnMembers | Colocar nodo secundario.
Realice los siguientes cambios en las propiedades del nodo:
- Establezca la propiedad DataSourceProperty en .
Department.Positions
- Establezca la propiedad DataSourcePropertyIsNullMode en .
SelectAll
- Establezca la propiedad DataSourceProperty en .
-
En la clase Contact (BusinessObjects\Contact.cs), reemplace la declaración de propiedad por el código siguiente:
Department
[Association("Department-Contacts", typeof(Department)), ImmediatePostData] public Department Department { get {return department;} set { SetPropertyValue(nameof(Department), ref department, value); // Clear Position and Manager properties if the Department has changed. if(!IsLoading) { Position = null; if(Manager != null && Manager.Department != value) { Manager = null; } } } }
-
Ejecute la aplicación. Abra la vista detallada de un departamento y vincule varios elementos de posición a este departamento.
-
Abra la vista detallada de un contacto que pertenezca a este departamento. El menú desplegable Editor de posiciones enumera las posiciones que vinculaste en el paso anterior:
Antes de continuar con esta sección del tutorial, debe familiarizarse con los siguientes conceptos básicos de eXpressApp Framework.
Acción
Visualmente, Action es un elemento de la barra de herramientas u otro control que realiza el código asociado cuando un usuario final lo manipula. XAF tiene varios tipos de acción predefinidos. Puede elegir el tipo adecuado en función de cómo desee que se muestre la acción dentro de la interfaz de usuario. Todas las acciones exponen el evento Execute cuyo controlador se ejecuta cuando los usuarios finales manipulan el elemento correspondiente. Para obtener más información, consulte el tema Acciones.
Controlador
Los controladores son clases heredadas de la clase Controller. Esta clase tiene los siguientes descendientes que también pueden servir como clases base para controladores:
- ViewController y sus versiones genéricas: ViewController y ObjectViewController<ViewType, ObjectType>
- WindowController
Los controladores implementan la lógica empresarial en la aplicación. Esta lógica se ejecuta automáticamente (por ejemplo, al activar una vista) o se activa cuando un usuario ejecuta una acción declarada dentro del controlador. XAF utiliza la reflexión para recopilar automáticamente los controladores implementados dentro de los módulos. Las clases de controlador deben ser públicas. Las propiedades del controlador y la clase base determinan una vista o una ventana donde este controlador está activo. Para obtener más información, consulte el tema Controladores.
Los controladores y las acciones son instrumentos que implementan características personalizadas en una aplicación XAF. En esta sección del tutorial, aprenderá cómo agregar acciones de diferentes tipos, implementar controladores sin acciones y modificar el comportamiento de controladores y acciones existentes. Se recomienda que complete las lecciones en el siguiente orden:
- Agregar una acción simple
- Agregar una acción parametrizada
- Agregar una acción que muestre una ventana emergente
- Agregar una acción con selección de opción
- Agregar una acción simple mediante un atributo
- Configuración del editor de acceso
- Configuración de control de cuadrícula de acceso
Esta lección explica cómo crear una acción simple.
Una acción simple es un botón que ejecuta código personalizado cuando un usuario hace clic en él.
Las instrucciones siguientes muestran cómo agregar el botón Borrar tareas a la Vista de detalles de contacto. Un clic en este botón borra todas las tareas rastreadas del contacto específico.
NOTA Antes de continuar, tómese un momento para repasar las lecciones anteriores:
- Agregar un controlador de vista. En el Explorador de soluciones, haga clic con el botón secundario en la carpeta Controllers del proyecto MySolution.Module y elija Agregar elemento DevExpress | Nuevo artículo... para invocar la Galería de plantillas. Seleccione los controladores XAF | Controlador de vista Plantilla de Visual Studio, especifique ClearContactTasksController como nombre del nuevo elemento y haga clic en Agregar elemento.
-
Visual Studio muestra un archivo ClearContactTasksController.cs generado automáticamente con una sola declaración de View Controller. En el constructor del controlador, especifique las propiedades del controlador:
using DevExpress.ExpressApp;
//... public partial class ClearContactTasksController : ViewController { public ClearContactTasksController() { InitializeComponent(); //Activate the Controller only in the Detail View TargetViewType = ViewType.DetailView; //Specify the type of objects that can use the Controller TargetObjectType = typeof(Contact); } // ...
Si no especifica la propiedad, la aplicación muestra las acciones del controlador para cada formulario de detalle.
TargetObjectType
PROPINA También puede crear un objeto genérico ViewController u ObjectViewController<ViewType, ObjectType> y especificar el tipo de destino como parámetro. Para obtener más información sobre cómo personalizar la funcionalidad del controlador, consulte el tema siguiente: Definir el ámbito de los controladores y las acciones.
ViewType
-
Agregue una nueva acción al controlador y un controlador para el evento de la acción:
Execute
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Actions; using DevExpress.Persistent.Base; using MySolution.Module.BusinessObjects; //... public partial class ClearContactTasksController : ViewController { public ClearContactTasksController() { InitializeComponent(); TargetViewType = ViewType.DetailView; TargetObjectType = typeof(Contact); SimpleAction clearTasksAction = new SimpleAction(this, "ClearTaskAction", PredefinedCategory.View) { //Specify the Action's button caption. Caption = "Clear tasks", //Specify the confirmation message that pops up when a user executes an Action. ConfirmationMessage = "Are you sure you want to clear the Tasks list?", //Specify the icon of the Action's button in the interface. ImageName = "Action_Clear" }; //This event fires when a user clicks the Simple Action control. clearTasksAction.Execute += ClearTasksAction_Execute; } private void ClearTasksAction_Execute(Object sender, SimpleActionExecuteEventArgs e) { while(((Contact)View.CurrentObject).Tasks.Count > 0) { ((Contact)View.CurrentObject).Tasks.Remove(((Contact)View.CurrentObject).Tasks[0]); ObjectSpace.SetModified(View.CurrentObject); } } // ...
Puede utilizar una de las imágenes estándar como icono del botón de la acción o importar la suya propia.
El punto de entrada principal de una acción simple es su evento Execute. Controle este evento para ejecutar código personalizado.
-
Ejecute la aplicación.
Abra un formulario de detalles para un elemento de contacto. Vincule varias tareas a este elemento y guárdelo.
Haga clic en el botón Borrar tareas. Aparecerá un mensaje de confirmación. Haga clic en Aceptar para eliminar todas las tareas del contacto actual.
TIP: Puede mostrar el botón de una acción en un diseño de vista detallada en lugar de en una barra de herramientas: Cómo: Incluir una acción en un diseño de vista detallada.
En esta lección se explica cómo agregar una acción parametrizada. La acción parametrizada muestra un editor que permite a los usuarios escribir un valor de parámetro antes de ejecutar la acción.
Las instrucciones siguientes muestran cómo implementar un nuevo controlador de vista con una acción parametrizada. Esta acción busca un objeto DemoTask por su valor de propiedad Subject y muestra el formulario de detalle del objeto encontrado.
NOTA Antes de continuar, tómese un momento para repasar las lecciones anteriores:
- Heredar de la clase de biblioteca de clase empresarial (núcleo XPO/EF))
- Inicialización de propiedades de objeto de negocio (núcleo XPO/EF))
- Agregar una acción simple
-
Agregue un nuevo controlador de View al proyecto MySolution.Module, como se describe en la lección Agregar una acción simple. Asígnele el nombre FindBySubjectController.
-
En MySolution.Module | Controladores | FindBySubjectController.cs archivo, especifique las propiedades del controlador:
using DevExpress.ExpressApp; // ... public partial class FindBySubjectController : ViewController { public FindBySubjectController() { InitializeComponent(); //Activate the controller only in the List View. TargetViewType = ViewType.ListView; //Activate the controller only for root Views. TargetViewNesting = Nesting.Root; //Specify the type of objects that can use the controller. TargetObjectType = typeof(DemoTask); } // ... }
Para obtener más información acerca de la vista raíz, consulte el tema siguiente: IsRoot.
-
Agregue una acción parametrizada al controlador:
public partial class FindBySubjectController : ViewController { public FindBySubjectController() { InitializeComponent(); TargetViewType = ViewType.ListView; TargetViewNesting = Nesting.Root; TargetObjectType = typeof(DemoTask); ParametrizedAction findBySubjectAction = new ParametrizedAction(this, "FindBySubjectAction", PredefinedCategory.View, typeof(string)) { ImageName= "Action_Search", NullValuePrompt = "Find task by subject..." }; findBySubjectAction.Execute += FindBySubjectAction_Execute; } // ... }
Un usuario envía una cadena en el editor de la acción. Esto provoca el evento ParametrizedAction.Execute de la acción.
-
Controlar el evento de la acción:
Execute
public partial class FindBySubjectController : ViewController { public FindBySubjectController() { // ... findBySubjectAction.Execute += FindBySubjectAction_Execute; } private void FindBySubjectAction_Execute(object sender, ParametrizedActionExecuteEventArgs e) { var objectType = ((ListView)View).ObjectTypeInfo.Type; IObjectSpace objectSpace = Application.CreateObjectSpace(objectType); string paramValue = e.ParameterCurrentValue as string; object obj = objectSpace.FindObject(objectType, CriteriaOperator.Parse("Contains([Subject], ?)", paramValue)); if(obj != null) { DetailView detailView = Application.CreateDetailView(objectSpace, obj); detailView.ViewEditMode = DevExpress.ExpressApp.Editors.ViewEditMode.Edit; e.ShowViewParameters.CreatedView = detailView; } } // ... }
Para obtener más información sobre la implementación del controlador de eventos, consulte la sección Explicación detallada.
-
Ejecute la aplicación.
Seleccione el elemento Tarea en el control de navegación (el editor Buscar tarea por asunto es la acción que implementó). Escriba una palabra del asunto de una tarea existente en este editor y presione Entrar. La aplicación muestra un formulario de detalles con esta tarea.
En XAF, se utiliza el espacio de objetos para consultar y actualizar objetos persistentes. Llame al método estático XafApplication.CreateObjectSpace para crear un espacio de objetos.
Utilice el método IObjectSpace.FindObject para buscar un objeto. Este método tiene los siguientes parámetros:DemoTask
- Tipo de los objetos mostrados en la vista de lista actual. Utilice View.ObjectTypeInfo.
- Criterios de búsqueda. Para generar un criterio, cree un objeto y pase componentes de criterios como parámetros del constructor. Para obtener más información, consulte la siguiente documentación de XPO: Sintaxis de criterios simplificados.
BinaryOperator
Para mostrar el objeto encontrado en una vista de detalles independiente:
- Llame al método XafApplication.CreateDetailView para crear una vista.
- Asigne la vista a la propiedad e.ShowViewParameters.CreatedView del parámetro de evento.
PROPINA Puede inicializar la propiedad en el controlador de eventos de cualquier acción de cualquier tipo. Esto le permite mostrar siempre una vista después de ejecutar una acción.
ShowViewParameters.Execute
Para obtener más información sobre cómo mostrar una vista en una ventana independiente, consulte el tema siguiente: Formas de mostrar una vista.
El objeto XafApplication es útil cuando necesita crear una vista de lista, una vista detallada, un espacio de objetos, etc. Un usuario puede acceder a un objeto desde muchas ubicaciones en una aplicación XAF. En Controllers, use Controller.Application para obtener dicho acceso.XafApplication
En esta lección se explica cómo crear una acción que muestre una ventana emergente. Este tipo de acción es útil cuando un usuario desea introducir varios parámetros en un cuadro de diálogo emergente antes de ejecutar una acción.
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
- Establecer una relación de varios a varios (núcleo XPO/EF))
- Agregar una acción simple
En este tutorial, implementará la capacidad de agregar notas de una lista predefinida a las descripciones de tareas.
-
Agregue el objeto de negocio de la biblioteca de clase empresarial a la aplicación. Para ello, agregue el código siguiente a MySolution.Module | Módulo.cs archivo:
Note
using DevExpress.Persistent.BaseImpl.EF; // ... public sealed partial class MySolutionModule : ModuleBase { public MySolutionModule() { // Adds a business object AdditionalExportedTypes.Add(typeof(Note)); } // ... }
-
Si está trabajando con EF Core, registre el tipo en . Edite el archivo BusinessObjects\MySolutionDbContext.cs como se muestra a continuación:
Note``DbContext
public class MySolutionEFCoreDbContext : DbContext { //... public DbSet<Note> Notes { get; set; } }
-
Si está trabajando con EF Core, agregue una migración y actualice la base de datos. Consulte la siguiente sección para obtener más información: Usar un DBMS: Migraciones de configuración.
-
Agregue un nuevo controlador de vistas al proyecto MySolution.Module. Asígnele el nombre PopupNotesController.
-
En el archivo PopupNotesController.cs, especifique las propiedades del controlador:
using DevExpress.ExpressApp; using DevExpress.Persistent.BaseImpl.EF; // ... public partial class PopupNotesController : ViewController { // ... public PopupNotesController() { InitializeComponent(); //Target the required Views and create their Actions TargetObjectType = typeof(DemoTask); TargetViewType = ViewType.DetailView; } // ... }
-
Agregue la acción y controle su evento:
ShowNotesAction``CustomizePopupWindowParams
public partial class PopupNotesController : ViewController { public PopupNotesController() { InitializeComponent(); TargetObjectType = typeof(DemoTask); TargetViewType = ViewType.DetailView; /*Invoke a pop-up window with a specified View and execute custom code when a user clicks the OK or Cancel button*/ PopupWindowShowAction showNotesAction = new PopupWindowShowAction(this, "ShowNotesAction", PredefinedCategory.Edit) { Caption = "Show Notes" }; showNotesAction.CustomizePopupWindowParams += ShowNotesAction_CustomizePopupWindowParams; } private void ShowNotesAction_CustomizePopupWindowParams(object sender, CustomizePopupWindowParamsEventArgs e) { IObjectSpace objectSpace = Application.CreateObjectSpace(typeof(Note)); string noteListViewId = Application.FindLookupListViewId(typeof(Note)); CollectionSourceBase collectionSource = Application.CreateCollectionSource(objectSpace, typeof(Note), noteListViewId); e.View = Application.CreateListView(noteListViewId, collectionSource, true); } // ... }
En este paso, controlará el evento PopupWindowShowAction.CustomizePopupWindowParams y establecerá la vista necesaria en el parámetro e.View del controlador. Este código crea la vista de lista de notas cuando genera la ventana emergente.
-
Controlar el evento de :
ShowNotesAction``Execute
// ... public PopupNotesController() { // ... showNotesAction.Execute += ShowNotesAction_Execute; } private void ShowNotesAction_Execute(object sender, PopupWindowShowActionExecuteEventArgs e) { DemoTask task = (DemoTask)View.CurrentObject; foreach(Note note in e.PopupWindowViewSelectedObjects) { if(!string.IsNullOrEmpty(task.Description)) { task.Description += Environment.NewLine; } // Add selected notes' text to a Task's description task.Description += note.Text; } View.ObjectSpace.CommitChanges(); }
El evento se produce cuando un usuario hace clic en Aceptar en la ventana emergente. El código del controlador de eventos anexa el valor de la propiedad al valor de la propiedad.
Execute``Note.Text``Task.Description
El parámetro e.PopupWindowViewSelectedObjects del controlador de eventos proporciona un objeto que un usuario selecciona en la ventana emergente.
-
Ejecute la aplicación.
Abra la vista de detalles de un elemento de tarea. La barra de herramientas Vista detallada muestra el botón Mostrar notas. Esta es la acción implementada en esta lección.
Haga clic en el botón para abrir la ventana emergente. La ventana emergente muestra una vista de lista para los objetos Note. Cree varios objetos Note.
Seleccione un objeto Note de la lista y haga clic en Aceptar. Después de eso, el valor de la propiedad Task.Description cambia.
TIP: Para obtener un ejemplo de cómo crear y mostrar una vista detallada, consulte el tema Cómo: Crear y mostrar una vista detallada del objeto seleccionado en una ventana emergente
En esta lección se explica cómo crear una acción que admita la selección de opciones.
En esta lección, implementará un nuevo controlador de vista con un archivo . Esta acción permitirá a los usuarios seleccionar valores para las propiedades SingleChoiceAction
, Task.Priority
yTask.Status
.
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
-
Agregue un nuevo controlador de vistas al proyecto MySolution.Module. Asígnele el nombre TaskActionsController.
-
En el archivo TaskActionsController.cs, establezca el :
TargetObjectType
using DevExpress.ExpressApp; // ... public partial class TaskActionsController : ViewController { public TaskActionsController() { InitializeComponent(); TargetObjectType = typeof(DemoTask); } // ... }
-
Agregue un y especifique sus propiedades:
SingleChoiceAction
public partial class TaskActionsController : ViewController { public TaskActionsController() { InitializeComponent(); TargetObjectType = typeof(DemoTask); SingleChoiceAction SetTaskAction = new SingleChoiceAction(this, "SetTaskAction", PredefinedCategory.Edit) { Caption = "Set Task", //Specify the display mode for the Action's items. Here the items are operations that you perform against selected records. ItemType = SingleChoiceActionItemType.ItemIsOperation, //Set the Action to become available in the Task List View when a user selects one or more objects. SelectionDependencyType = SelectionDependencyType.RequireMultipleObjects }; } // ... }
-
Para rellenar la acción con elementos, rellene la colección ChoiceActionBase.Items de la acción en el constructor del controlador:
public partial class TaskActionsController : ViewController { private ChoiceActionItem setPriorityItem; private ChoiceActionItem setStatusItem; public TaskActionsController() { // ... setPriorityItem = new ChoiceActionItem(CaptionHelper.GetMemberCaption(typeof(DemoTask), "Priority"), null); SetTaskAction.Items.Add(setPriorityItem); FillItemWithEnumValues(setPriorityItem, typeof(Priority)); setStatusItem = new ChoiceActionItem(CaptionHelper.GetMemberCaption(typeof(DemoTask), "Status"), null); SetTaskAction.Items.Add(setStatusItem); FillItemWithEnumValues(setStatusItem, typeof(DevExpress.Persistent.Base.General.TaskStatus)); } private void FillItemWithEnumValues(ChoiceActionItem parentItem, Type enumType) { EnumDescriptor ed = new EnumDescriptor(enumType); foreach(object current in ed.Values) { ChoiceActionItem item = new ChoiceActionItem(ed.GetCaption(current), current); item.ImageName = ImageLoader.Instance.GetEnumValueImageName(current); parentItem.Items.Add(item); } } }
El ejemplo de código anterior organiza los elementos de la colección Action como un árbol:
Items
- El nivel raíz contiene elementos cuyos títulos corresponden a los nombres de las propiedades y. El objeto CaptionHelper devuelve títulos de elemento.
DemoTask.Priority``DemoTask.Status
- El nivel anidado contiene los valores y enumeración. El objeto EnumDescriptor devuelve títulos de elementos.
Priority``Status
Al rellenar la colección ChoiceActionBase.Items en un constructor Controller, como se muestra en el código anterior, puede utilizar ActionDesign | del Editor de modelos. Acciones | | ChoiceActionItems para establecer un nombre de imagen, un acceso directo y un título localizado para los elementos agregados.
Si rellena la colección en un controlador de eventos Controller.Activated, el Editor de modelos no carga elementos.
Items
- El nivel raíz contiene elementos cuyos títulos corresponden a los nombres de las propiedades y. El objeto CaptionHelper devuelve títulos de elemento.
-
Abra el archivo Task.cs y asigne imágenes al valor de enumeración como en el ejemplo de código siguiente:
Priority
public enum Priority { [ImageName("State_Priority_Low")] Low, [ImageName("State_Priority_Normal")] Normal, [ImageName("State_Priority_High")] High }
En este tutorial, los valores de enumeración tienen los atributos ImageNameAttribute para establecer imágenes para estos valores en la interfaz de usuario.
XAF se incluye con la biblioteca de imágenes estándar. La biblioteca incluye el
State_Priority_Low
,State_Priority_Normal
yState_Priority_High
, y las imágenes utilizadas en esta lección.` -
Controle el evento SingleChoiceAction.Execute que se produce cuando un usuario elige el elemento de la acción:
public partial class TaskActionsController : ViewController { // ... public TaskActionsController() { // ... SetTaskAction.Execute += SetTaskAction_Execute; } private void SetTaskAction_Execute(object sender, SingleChoiceActionExecuteEventArgs e) { /*Create a new ObjectSpace if the Action is used in List View Use this ObjectSpace to manipulate the View's selected objects.*/ IObjectSpace objectSpace = View is ListView ? Application.CreateObjectSpace(typeof(DemoTask)) : View.ObjectSpace; ArrayList objectsToProcess = new ArrayList(e.SelectedObjects); if(e.SelectedChoiceActionItem.ParentItem == setPriorityItem) { foreach(Object obj in objectsToProcess) { DemoTask objInNewObjectSpace = (DemoTask)objectSpace.GetObject(obj); objInNewObjectSpace.Priority = (Priority)e.SelectedChoiceActionItem.Data; } } else if(e.SelectedChoiceActionItem.ParentItem == setStatusItem) { foreach(Object obj in objectsToProcess) { DemoTask objInNewObjectSpace = (DemoTask)objectSpace.GetObject(obj); objInNewObjectSpace.Status = (DevExpress.Persistent.Base.General.TaskStatus)e.SelectedChoiceActionItem.Data; } } objectSpace.CommitChanges(); View.ObjectSpace.Refresh(); } }
Para obtener acceso a un elemento de acción seleccionado, use el parámetro e.SelectedChoiceActionItem del controlador de eventos.
Cree un elemento independiente para editar varios objetos que se muestran actualmente. Este enfoque mejora el rendimiento, ya que cada cambio de objeto no desencadena los eventos del control de cuadrícula.
ObjectSpace
-
Ejecute la aplicación. Seleccione el elemento Tarea en el control de navegación. Después de eso, la acción Establecer tarea se activa.
Para cambiar la propiedad Priority o Status de los objetos Task seleccionados, seleccione un elemento en la lista desplegable Action:
En esta lección se explica cómo utilizar los métodos de un objeto de negocio para agregar una acción simple.
Las instrucciones siguientes muestran cómo agregar un nuevo método con el atributo ActionAttribute a la clase.DemoTask
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
- Establecer una relación de varios a varios (núcleo XPO/EF))
- Agregar una acción simple
-
Agregue el método
Postpone
a la claseDemoTask
:namespace MySolution.Module.BusinessObjects [DefaultClassOptions] [ModelDefault("Caption", "Task")] public class DemoTask : DevExpress.Persistent.BaseImpl.EF.Task { //... /*Use this attribute to display the Postpone button in the UI and call the Postpone() method when a user clicks this button*/ [Action(ToolTip = "Postpone the task to the next day")] //Shift the task's due date forward by one day public void Postpone() { if(DueDate == DateTime.MinValue) { DueDate = DateTime.Now; } DueDate = DueDate + TimeSpan.FromDays(1); } }
PROPINA Puede utilizar el atributo para implementar una acción que pida a un usuario que especifique parámetros en un cuadro de diálogo emergente (por ejemplo, el número de días para posponer una tarea). Consulte el tema siguiente para obtener un ejemplo: Cómo: Crear una acción mediante el atributo action.
Action
-
Muestre la columna Fecha de vencimiento en la Vista Lista de tareas. Abra MySolution.Module | Archivo ModelDesignedDiffs.xafml. En el Editor de modelos, haga lo siguiente:
-
Ir a Vistas | MySolution.Module.BusinessObjects | DemoTask | DemoTask_ListView | Columnas.
-
Haga clic con el botón secundario en el encabezado de cuadrícula y haga clic en el elemento Selector de columnas.
-
Arrastre la columna Fecha de vencimiento a la vista y guarde el archivo ModelDesignedDiffs.xafml.
-
-
Ejecute la aplicación. Seleccione el elemento Tarea en el control de navegación.
Seleccione una o más tareas en la Vista Lista de tareas. Aparecerá el botón Posponer acción. Haga clic en este botón. La fecha de vencimiento de las tareas seleccionadas se adelanta un día.
En esta lección se explica cómo acceder a los editores en una vista detallada y cambiar su configuración.
Las instrucciones siguientes muestran cómo hacer que el editor de propiedades Cumpleaños muestre un selector de fecha desplazable en su ventana desplegable.
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
- Heredar de la clase de biblioteca de clase empresarial (núcleo XPO/EF))
- Agregar una acción simple
-
En el proyecto MySolution.Blazor.Server, agregue un controlador de View a la carpeta Controllers. Asigne al nuevo controlador el nombre "DateEditCalendarController". Especifique la clase antecesora del controlador ObjectViewController<ViewType, ObjectType>:
using DevExpress.ExpressApp; // ... public partial class DateEditCalendarController : ObjectViewController<DetailView, Contact> { public DateEditCalendarController() { InitializeComponent(); } // ... }
El hereda de la clase base ObjectViewController<ViewType, ObjectType>. Los parámetros de la clase base habilitan el controlador solo para vistas detalladas que muestran y editan objetos.
DateEditCalendarController
-
Anule el método. Utilice el método DetailViewExtensions.CustomizeViewItemControl para tener acceso a la configuración del editor de propiedades:
OnActivated``Birthday
namespace MySolution.Blazor.Server.Controllers { public partial class DateEditCalendarController : ObjectViewController<DetailView, Contact> { public DateEditCalendarController() { InitializeComponent(); } protected override void OnActivated() { base.OnActivated(); //Access the Birthday property editor settings View.CustomizeViewItemControl<DateTimePropertyEditor>(this, SetCalendarView, nameof(Contact.Birthday)); } private void SetCalendarView(DateTimePropertyEditor propertyEditor) { //Obtain the Component Adapter var dateEditAdapter = (DxDateEditAdapter)propertyEditor.Control; //Set the date picker display mode to scroll picker dateEditAdapter.ComponentModel.PickerDisplayMode = DevExpress.Blazor.DatePickerDisplayMode.ScrollPicker; } } }
Utilice la propiedad Adaptador de componentes para tener acceso a las propiedades ASP.NET reales del componente Core Blazor.
ComponentModel
Para obtener información general sobre la arquitectura del Editor de propiedades y los controles de interfaz de usuario usados por XAF, revise los siguientes artículos:
-
Ejecute la aplicación y abra la Vista de detalles de contacto. El editor de cumpleaños muestra un selector de fecha desplazable en su ventana desplegable:
En esta lección se explica cómo tener acceso a las propiedades de un componente de cuadrícula que se muestra en una vista de lista.
Las instrucciones siguientes describen la implementación de un nuevo controlador de vista. Este controlador permite que las operaciones cambien el tamaño de las columnas.
NOTA Antes de continuar, tómese un momento para repasar la siguiente lección:
-
En el proyecto MySolution.Blazor.Server, agregue un controlador de View a la carpeta Controllers. Asigne a este controlador el nombre ColumnResizeModeViewController.
-
Especifique la clase antecesora del controlador y reemplace el método:
ViewController<ListView>
OnViewControlsCreated
using DevExpress.ExpressApp; using DevExpress.ExpressApp.Blazor.Editors; namespace MySolution.Blazor.Server.Controllers { public partial class ColumnResizeModeViewController : ViewController<ListView> { public ColumnResizeModeViewController() { InitializeComponent(); } // ... protected override void OnViewControlsCreated() { base.OnViewControlsCreated(); if (View.Editor is DxGridListEditor gridListEditor) { //Obtain the Component Adapter IDxGridAdapter dataGridAdapter = gridListEditor.GetGridAdapter(); //Access grid component properties and specify how exactly a user can resize columns dataGridAdapter.GridModel.ColumnResizeMode = DevExpress.Blazor.GridColumnResizeMode.ColumnsContainer; } } // ... } }
-
Ejecute la aplicación. Intente cambiar el tamaño de una columna en un componente de cuadrícula en cualquier vista de lista. El ancho del contenedor de cuadrícula cambia, mientras que las otras columnas conservan su ancho.
En esta sección del tutorial se explica cómo personalizar la interfaz de usuario generada automáticamente.
Los elementos visuales de la aplicación XAF se basan en las clases de datos que se declaran y en la información de los ensamblados a los que hace referencia la aplicación. Toda la información recibida son metadatos: datos que definen la estructura de la base de datos y las características de la aplicación en un formato neutral que puede adoptar para cualquier plataforma de destino. Estos metadatos se denominan modelo de aplicación. Es una herramienta poderosa que le permite realizar cambios en su aplicación.
Para personalizar el modelo de aplicación en tiempo de diseño, utilice el Editor de modelos. Se abre directamente desde Visual Studio.
Las siguientes lecciones explican cómo usar el Editor de modelos:
- Colocar una acción en una ubicación diferente
- Especificar la configuración de la acción
- Dar formato a un título de objeto de negocio
- Crear una propiedad calculada
- Dar formato a un valor de propiedad
- Usar un editor multilínea para las propiedades de cadena
- Agregar un elemento al control de navegación
- Implementar la validación del valor de la propiedad en el modelo de aplicación
- Personalizar el diseño Ver elementos
- Localizar elementos de la interfaz de usuario
- Agregar un editor a una vista de detalles
- Cambiar la visibilidad de campo en una vista de lista
- Filtrar vistas de lista
- Lista de grupos Ver datos
Si la opción requerida no está disponible en el Editor de modelos, puede acceder directamente a las opciones de los controles utilizados en la aplicación. Revise los siguientes temas para obtener más información:
- Configuración del editor de acceso
- Configuración de componentes de cuadrícula de vista de lista de acceso mediante un controlador
En esta lección se explica cómo mover una acción a un contenedor de acciones diferente.
Un contenedor de acciones es un control que muestra una acción o un conjunto de acciones.
Las instrucciones siguientes explican cómo mover el del contenedor de acción de vista al contenedor de acción de edición.ClearTasksAction
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos.
-
En el Editor de modelos, vaya a ActionDesign | Nodo ActionToContainerMapping. Expanda el nodo Vista que es el contenedor de acciones de Vista. Arrastre el nodo secundario ClearTasksAction al nodo Editar. Establezca el índice del nodo en .
0
Los nodos secundarios del nodo ActionToContainerMapping corresponden a los contenedores de acciones de la aplicación. Las acciones se asignan a contenedores de acciones según los valores de la propiedad Category.
Cuando definió el en la lección Agregar una acción simple, estableció la propiedad Category en . es un valor de la enumeración que corresponde al contenedor de acciones de vista.
ClearTasksAction``View``View``DevExpress.Persistent.Base.PredefinedCategory
-
Ejecute la aplicación. En la vista Detalles del contacto, el botón Borrar tarea aparece a la izquierda del botón Eliminar.
PROPINA Puede controlar el evento ActionControlsSiteController.CustomizeContainerActions para cambiar la ubicación de una acción en el código.
En esta lección se explica cómo modificar las propiedades de Action.
Las instrucciones siguientes explican cómo cambiar la información sobre herramientas y el mensaje de confirmación de ClearTasksAction. Esta acción se definió en la lección Agregar una acción sencilla.
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos.
-
En el Editor de modelos, vaya a ActionDesign | Nodo Acciones. Cambie los valores de propiedad del nodo ClearTasksAction de la siguiente manera:
- Establezca la propiedad Información sobre herramientas en .
Clear the current Contact's tasks
- Establezca la propiedad ConfirmationMessage en .
Are you sure you want to clear all the tasks?
- Establezca la propiedad Información sobre herramientas en .
-
Ejecute la aplicación y abra la Vista de detalles de contacto. Desplace el puntero del mouse sobre el botón Borrar tareas para ver la información sobre herramientas.
-
Haga clic en el botón para mostrar el mensaje de confirmación.
En esta lección se explica cómo dar formato a un título del formulario de detalles de un objeto de negocio.
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
- Heredar de la clase de biblioteca de clase empresarial (núcleo XPO/EF))
- Colocar una acción en una ubicación diferente
- Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos.
- En el Editor de modelos, desplácese hasta BOModel | Nodo MySolution.Module.BusinessObjects. Seleccione el nodo Contacto.
- Establezca el valor de la propiedad ObjectCaptionFormat en las propiedades de clase que se muestran a la derecha.
{0:FullName} from {0:Department}
- Ejecute la aplicación. Abra el formulario de detalles de un objeto Contact. Ahora puedes ver el título personalizado:
En esta lección se explica cómo crear propiedades calculadas.
Las instrucciones siguientes explican cómo agregar una clase Payment con las siguientes propiedades:
- Tasa (una propiedad persistente)
- Horas (una propiedad persistente)
- Importe (una propiedad calculada no persistente:
Amount = Rate * Hours
)
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
- Heredar de la clase de biblioteca de clase empresarial (núcleo XPO/EF))
- Colocar una acción en una ubicación diferente
-
Cree un objeto de negocio en el proyecto MySolution.Module.
Payment
-
Reemplace la declaración de clase generada por el código siguiente:
using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl; using DevExpress.Xpo; // ... [DefaultClassOptions] public class Payment : BaseObject { public Payment(Session session) : base(session) { } private double rate; public double Rate { get { return rate; } set { if(SetPropertyValue(nameof(Rate), ref rate, value)) OnChanged(nameof(Amount)); } } private double hours; public double Hours { get { return hours; } set { if(SetPropertyValue(nameof(Hours), ref hours, value)) OnChanged(nameof(Amount)); } } /*Use this attribute to specify that the value of this property depends on the values of other fields. The expression that you pass as a parameter calculates the property value.*/ [PersistentAlias("Rate * Hours")] public double Amount { get { return (double)(EvaluateAlias(nameof(Amount)) ?? 0); } } }
La propiedad no tiene descriptor de acceso. Su cálculo del valor tiene lugar en el descriptor de acceso.
Amount``set``get
-
Para aplicaciones basadas en EF Core, registre el tipo
Payment
en elDbContext
:public class MySolutionEFCoreDbContext : DbContext { //... public DbSet<Payment> Payments { get; set; } }
-
Para aplicaciones basadas en EF Core, agregue una migración y actualice la base de datos. Consulte la siguiente sección para obtener más información: Usar un DBMS: Migraciones de configuración.
-
Ejecute la aplicación. Seleccione el elemento de pago en el control de navegación y haga clic en "Nuevo". En la vista Detalles de pago, cambie las propiedades Tarifa y Horas para ver cómo afecta esto a la propiedad Importe.
En esta lección se explica cómo dar formato a una propiedad de clase empresarial y especificar su configuración de máscara de entrada.
En esta lección, personalizará el formato de presentación para el Task.StartDate
Task.DueDate
Task.PercentCompleted
, y las propiedades en el Editor de modelos.
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
- Heredar de la clase de biblioteca de clase empresarial (núcleo XPO/EF))
- Colocar una acción en una ubicación diferente
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos.
-
Vaya a la lista de materiales | DevExpress.Persistent.BaseImpl.EF | Tarea | Nodo OwnMembers.
-
Para los nodos secundarios DueDate y StartDate, establezca el valor de la propiedad DisplayFormat en - un patrón de fecha largo.
D
Tenga en cuenta que el valor de la propiedad EditMask es - un patrón de día corto.
d
-
Para el nodo secundario PercentCompleted, establezca la propiedad DisplayFormat en .
{0:N0}%
-
Ejecute la aplicación. Invoque una lista de detalles para la clase DemoTask.
Note how text format changes when StartDate and DueDate editors receive or lose focus. If you focus an editor, its EditMask takes effect ( - short date pattern). If an editor loses input focus, its DisplayFormat takes over ( - long date pattern).
d``D
The PercentCompleted display text includes the percentage sign: ‘%’.
NOTE In .NET 5, the libraries used for globalization functionality has been changed. Refer to the following topic for details: Globalization APIs use ICU libraries on Windows. If a current thread’s culture is set to a culture that includes only the language and not the country (for example, “de” or “en”), the currency symbol renders as an international currency symbol (), for example: . Refer to the following topics for details:
¤``100,00 ¤
This lesson explains how to display a multiline editor for string properties.
The instructions below explain how to enable a multiline text box for the Web Page Address property editor in the Contact Detail View.
-
Open the Model.DesignedDiffs.xafml file in the Model Editor.
-
Navigate to the BOModel | MySolutuon.Module.BusinessObjects | Contact | OwnMembers node.
-
For the WebPageAddress child node, set the properties as follows:
-
Set the RowCount property to .
2
This creates a two-line editor for the WebPageAddress property.
-
Set the Size property to .
100
This allows a user to enter up to 100 symbols.
You can also apply the FieldSize attribute in code.
-
-
Ejecute la aplicación. Abra una lista de detalles para un objeto Contact. La propiedad Dirección de página Web utiliza un editor de cuadros de texto de dos líneas.
En esta lección se explica cómo agregar un elemento al control de navegación.
Las instrucciones siguientes describen cómo agregar el elemento Notas al control de navegación. Cuando un usuario hace clic en este elemento, la aplicación muestra una vista de lista para la clase empresarial Note agregada en la lección siguiente: Agregar una acción que muestre una ventana emergente.
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos. En la vista de árbol, navegue hasta NavigationItems | Artículos | Predeterminado | Nodo Elementos. Para agregar un elemento secundario a un elemento de navegación, haga clic con el botón secundario en el nodo Elementos y seleccione Agregar... | NavigationItem en el menú contextual:
-
Especifique las siguientes propiedades para el nuevo elemento:
- Establezca la propiedad View en .
Note_ListView
- Establezca la propiedad Caption en .
Notes
- Establezca la propiedad Id en .
Note
- Establezca la propiedad View en .
-
Ejecute la aplicación. Puede ver el nuevo elemento de navegación que le permite agregar y editar notas de texto sin formato.
En esta lección se explica cómo comprobar si el valor de una propiedad cumple unos criterios predefinidos. Esta funcionalidad estará disponible si instala el módulo de validación.
Las instrucciones siguientes explican cómo evitar que un usuario marque una tarea como completada antes de que la tarea haya comenzado ( es ).DemoTask.Status
NotStarted
NOTA Antes de continuar, tómese un momento para repasar la siguiente lección:
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos. Vaya a la Validación | Nodo Reglas. Agregar una nueva regla de validación: haga clic con el botón derecho en el nodo Reglas y seleccione Agregar... | RuleCriteria.
-
Establezca los valores de las siguientes propiedades para el nodo:
- TargetType a "MySolution.Module.BusinessObjects.DemoTask"
- Criterios para
Status != 'NotStarted'
- ID a
TaskStarted
- TargetContextIDs a
MarkCompleted
- CustomMessageTemplate para
Cannot set the task as completed because it has not started.
El valor de la propiedad Criteria debe respetar la sintaxis del lenguaje Criteria. Para definir los criterios, haga clic en el botón de puntos suspensivos () situado a la derecha del valor Criterios e invoque el cuadro de diálogo Generador de filtros. En este cuadro de diálogo, puede diseñar visualmente una expresión de criterio.
-
En el ActionDesign | Acciones | Task.MarkCompleted, establezca la propiedad ValidationContexts en .
MarkCompleted
PROPINA Puede utilizar los contextos Guardar o Eliminar. La validación de reglas con estos contextos se produce cuando un usuario guarda o elimina un objeto (consulte Reglas de validación).
-
Cambie el título de la acción MarkCompleted a .
Mark Completed
-
Ejecute la aplicación. Asigne el valor "Not Started" a la propiedad Status de uno de los objetos DemoTask existentes. Haga clic en el botón Marcar completado. Aparece el siguiente cuadro de diálogo Error de validación:
También puede agregar una regla a una clase o propiedad en el código. Para obtener información adicional, consulte el tema siguiente: Implementar la validación del valor de la propiedad en el código (XPO).
En el tema siguiente se enumeran todos los tipos de reglas disponibles y sus descripciones: Reglas de validación.
En esta lección se explica cómo personalizar el diseño predeterminado del editor en una vista de detalles. Las instrucciones siguientes utilizan la vista de detalles de contacto como ejemplo.
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos.
-
Navegar a las vistas | MySolution.Module.BusinessObjects | Contacto | Contact_DetailView | Nodo de diseño.
-
El Editor de modelos muestra una superficie de diseño que imita la vista Detalles de contacto. Para cambiar el diseño del editor, haga clic con el botón derecho en el espacio vacío de la vista y elija Personalizar diseño.
El formulario Personalización le permite agregar, quitar y reordenar elementos.
-
Para quitar un elemento, arrástrelo desde la Vista de detalles al formulario de personalización.
-
Para agregar un elemento, arrástrelo desde el formulario de personalización a la vista de detalles.
-
Para reordenar los elementos, arrastre los editores para crear un nuevo diseño y guardar los cambios.
Para obtener más información sobre el formulario Personalización y la ficha Vista de árbol de diseño y su menú contextual, consulte el tema Personalización predeterminada en tiempo de ejecución.
-
-
Explore las opciones adicionales de personalización de diseño disponibles en el menú contextual. Haga clic en la ficha Vista de árbol de diseño del formulario de personalización. Haga clic con el botón secundario en un nodo de árbol para invocar un menú contextual.
-
Ejecute la aplicación para ver el nuevo diseño de la vista de detalles de contacto.
PROPINA Para restablecer los cambios realizados en el diseño, haga clic con el botón derecho en Contact_DetailView | Diseño y elija Restablecer diferencias.
En esta lección se explica cómo localizar una aplicación XAF ASP.NET Core Blazor. Describe cómo traducir elementos de la interfaz de usuario al alemán y crear una aplicación multilingüe.
NOTA Para obtener más información sobre la localización, revise los siguientes temas:
-
Agregue los paquetes DevExpress.ExpressApp.de, DevExpress.ExpressApp.Blazor.de y DevExpress.ExpressApp.Security.de al proyecto MySolution.Blazor.Server.
Los paquetes están disponibles solo para los siguientes idiomas: alemán (de), español (es) y japonés (ja). Para otros idiomas, utilice el servicio de localización para descargar ensamblados satélite. Consulte el tema Localizar módulos XAF estándar y controles DevExpress utilizados en una aplicación para obtener más información sobre cómo usar este servicio para localizar módulos XAF.
-
En el proyecto MySolution.Blazor.Server, abra el archivo appsettings.json. Agregue el idioma alemán a la sección DevExpress:ExpressApp:Languages y habilite el selector de idioma en tiempo de ejecución:
{ // ... "DevExpress": { "ExpressApp": { "Languages": "en;de", "ShowLanguageSwitcher": true, // ... } } }
Consulte la sección de ayuda Referencia cultural actual en aplicaciones XAF ASP.NET Core Blazor para obtener más información sobre cómo una aplicación XAF ASP.NET Core Blazor determina el idioma predeterminado.
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos. Enfoque el nodo MiSolución y haga clic en Administrador de idiomas... en el cuadro combinado Idioma de la barra de herramientas del Editor de modelos.
-
Agregue el idioma de destino en el cuadro de diálogo invocado y haga clic en Aceptar.
-
Reinicie Visual Studio para cargar valores localizados de ensamblados satélite.
-
En el Explorador de soluciones, haga clic con el botón secundario en el archivo Model.DesignedDiffs.Localization.de.xafml y abra la ventana Propiedades. Asegúrese de que el campo Acción de compilación esté establecido en Recurso incrustado.
-
Seleccione el idioma recién agregado en el cuadro combinado Idioma.
-
Los paquetes de localización traducen cadenas/mensajes estándar utilizados en XAF. También debe traducir las cadenas que son exclusivas de la aplicación actual (como los nombres de objetos o propiedades). Para ello, localice las propiedades indicadas por el glifo "globo" en todos los nodos y nodos secundarios y asígneles una traducción al alemán.
-
Ejecute la aplicación. Haga clic en el icono de engranaje para mostrar el menú de configuración y cambiar el idioma a alemán.
En esta lección se explica cómo hacer que una propiedad (su editor) sea visible en una vista de detalles. Las instrucciones siguientes muestran cómo localizar la propiedad anidada Department.Office y hacerla visible en la Vista de detalles de contacto.
NOTA Antes de continuar, tómese un momento para repasar la siguiente lección:
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos.
-
Navegar a las vistas | MySolution.Module.BusinessObjects | Nodo de contacto. Expanda el nodo secundario Contact_DetailView y haga clic en el nodo Diseño.
-
El Editor de modelos muestra una superficie de diseño que imita la vista Detalles de contacto. Haga clic con el botón derecho en el espacio vacío de la vista y elija Personalizar diseño.
-
En la ventana Personalización invocada, haga clic en el botón Agregar.
-
En el cuadro de diálogo Modelo de objetos, expanda el nodo Departamento, active la casilla Office y haga clic en Aceptar.
-
El elemento Office: aparece en la pestaña Elementos ocultos de la ventana Personalización:
-
Arrastre el elemento Office: a la posición requerida de la Vista de detalles de contacto.
-
Ejecute la aplicación, abra la Vista de detalles de contacto y busque el editor de Office:
En esta lección se explica cómo seleccionar las columnas mostradas en una vista de lista. Los pasos siguientes describen cómo personalizar la vista Lista de contactos en tiempo de diseño.
NOTA Antes de continuar, tómese un momento para repasar la siguiente lección:
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos.
-
Haga clic en el botón Vistas | MySolution.Module.BusinessObjects | Contact_ListView | Nodo Columnas para abrir el Diseñador del Editor de listas de cuadrículas. Haga clic con el botón derecho en el encabezado de la tabla y seleccione Selector de columnas.
-
Arrastre los elementos hacia y desde la ventana Personalización para mostrar las siguientes columnas en la vista de lista: Nombre completo, Departamento, Puesto y Correo electrónico.
También puede cambiar el tamaño y agrupar columnas en el Diseñador del editor de listas de cuadrículas. Consulte la siguiente sección de ayuda para obtener más información: Personalización en tiempo de diseño.
Para restablecer la configuración de columna, haga clic con el botón derecho en Vistas | MySolution.Module.BusinessObjects | Contact_ListView | Columnas y seleccione Restablecer diferencias.
-
Ejecute la aplicación. La vista Lista de contactos muestra las columnas Nombre completo, Departamento, Puesto y Correo electrónico.
En esta lección se describen tres técnicas utilizadas para filtrar una vista de lista. Los filtros se aplicarán a la vista Lista de contactos.
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
- Heredar de la clase de biblioteca de clase empresarial (núcleo XPO/EF))
- Implementar clases empresariales personalizadas y propiedades de referencia (núcleo XPO/EF))
- Establecer una relación de uno a varios (XPO/EF)
- Filtrar origen de datos para un editor de búsquedas (XPOEF Core
- Colocar una acción en una ubicación diferente
Esta técnica permite a los usuarios finales aplicar filtros predefinidos a una vista de lista.
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos. Navegar a las vistas | MySolution.Module.BusinessObjects | Contact_ListView nodo. Haga clic con el botón derecho en el nodo secundario Filtros y seleccione Agregar | ListViewFilterItem. Para el nuevo nodo, establezca la propiedad Id en Contactos del departamento de desarrollo. Establezca la propiedad Criteria en .
[Department.Title] = 'Development Department'
Las propiedades Criteria utilizan la sintaxis del lenguaje de criterios.
También puede crear un criterio de filtro en el cuadro de diálogo Generador de filtros. Para abrir este cuadro de diálogo, haga clic en el botón de puntos suspensivos () situado a la derecha del valor Criterios.
-
Agregue otro nodo secundario al nodo Filtros. Establezca la propiedad Id en Developers y la propiedad Criteria en .
[Position.Title] = 'Developer'
-
Agregue un nodo secundario más al nodo Filtros. Establezca la propiedad Id en Todos los contactos y deje vacía la propiedad Criterios. Este elemento mostrará todos los objetos Contact en la vista de lista.
-
Para el nodo Filters, establezca la propiedad CurrentFilter en Developers. El filtro Desarrolladores se aplicará inicialmente a la vista Lista de contactos.
-
Ejecute la aplicación y compruebe que la acción SetFilter está disponible.
El Editor de modelos también permite filtrar los registros de la vista de lista sin ninguna indicación en la interfaz de usuario.
-
En el proyecto MySolution.Module, abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos. Navegar a las vistas | MySolution.Module.BusinessObjects | Contacto | Contact_ListView nodo. Establezca su propiedad Criteria en .
Position.Title = 'Developer'
-
Ejecute la aplicación y compruebe que la vista Lista de contactos muestra solo desarrolladores.
Puede crear filtros que no se pueden deshabilitar en la interfaz de usuario de la aplicación ni en el Editor de modelos.
-
En el Explorador de soluciones, haga clic con el botón secundario en la carpeta Controllers del proyecto MySolution.Module y elija Agregar elemento DevExpress | Nuevo artículo... para invocar la Galería de plantillas.
-
Seleccione los controladores XAF | Controlador de vista Plantilla de Visual Studio. Especifique FilterListViewController como nombre del nuevo elemento y haga clic en Agregar elemento.
-
En el archivo FilterListViewController.cs generado automáticamente, herede el controlador de ObjectViewController<ViewType, ObjectType>:
using DevExpress.Data.Filtering; using DevExpress.ExpressApp; using MySolution.Module.BusinessObjects; // ... public partial class FilterListViewController : ObjectViewController<DetailView, Contact> { public FilterListViewController() { InitializeComponent(); } // ... }
-
Anule el método:
OnActivated
public partial class FilterListViewController : ObjectViewController<DetailView, Contact> { // ... protected override void OnActivated() { base.OnActivated(); //Specify a filter criteria. View.CollectionSource.Criteria["Developers"] = CriteriaOperator.FromLambda<Contact>(c => c.Position.Title == "Developer"); } // ... }
-
Ejecute la aplicación y compruebe el filtro en la vista Lista de contactos.
En este tema se explica cómo agrupar datos de vista de lista y se usan las propiedades Departamento y Posición creadas en los pasos anteriores para agrupar los datos de la vista de lista de contactos.
NOTA Antes de continuar, tómese un momento para repasar la siguiente lección:
-
Abra el archivo Model.DesignedDiffs.xafml en el Editor de modelos.
-
Haga clic en el botón Vistas | MySolution.Module.BusinessObjects | Contacto | Contact_ListView | Nodo Columnas para abrir el Diseñador del Editor de listas de cuadrículas. Haga clic con el botón secundario en el encabezado de la tabla y seleccione el elemento Mostrar grupo por cuadro.
-
El panel Grupo aparece encima de los encabezados de columna.
-
Arrastre los encabezados de columna Departamento y Posición al Panel Grupo. Tenga en cuenta que varias columnas en el área de grupo crean grupos anidados.
Cuando se agrega una columna al Panel de grupos, el valor de la propiedad de la columna cambia. También puede especificar directamente la propiedad de una columna para agrupar los datos de la vista de lista. Consulte el tema siguiente para obtener más información: Personalización de columnas de vista de lista.
GroupIndex
GroupIndex
Puede ocultar el Panel de grupo para evitar que los usuarios cambien de grupo. Navegar a las vistas | MySolution.Module.BusinessObjects | Contacto | Contact_ListView nodo y establezca su propiedad IsGroupPanelVisible en .
False
-
Ejecute la aplicación. La vista Lista de contactos se agrupa por los campos Departamento y Posición y se muestra el Panel de grupo.
-
Users can also drag columns to and from the Group Panel to group and ungroup List View Data.
eXpressApp Framework proporciona algunas características en ensamblajes separados llamados módulos. Para obtener información sobre cómo agregar y usar estas características en las aplicaciones, vea las siguientes lecciones:
En esta lección se describe cómo adjuntar colecciones de archivos a objetos de negocio. En este tutorial, agregaremos el módulo de archivos adjuntos a una aplicación ASP.NET Core Blazor, e implementaremos nuevas clases de negocio: para almacenar la información del currículum de un contacto y para guardar elementos de recopilación de datos de archivos.Resume
PortfolioFileData
NOTA Antes de continuar, tómese un momento para repasar las siguientes lecciones:
-
Agregue el paquete NuGet DevExpress.ExpressApp.FileAttachment.Blazor al proyecto MySolution.Blazor.Server. Consulte el tema siguiente para obtener más información sobre cómo instalar paquetes NuGet de DevExpress: Instalar controles de DevExpress mediante paquetes NuGet.
-
En el archivo Startup.cs, llame al método AddFileAttachments(IModuleBuilder, Action) para agregar el módulo de datos adjuntos de archivo a la aplicación:
public class Startup { // ... public void ConfigureServices(IServiceCollection services) { // ... services.AddXaf(Configuration, builder => { builder.UseApplication<MySolutionBlazorApplication>(); builder.Modules .AddConditionalAppearance() // ... .AddFileAttachments() // ... }); // ... } }
Si agrega el módulo de datos adjuntos de archivos al crear una aplicación XAF, el Asistente para soluciones genera el código utilizado para agregar automáticamente el módulo de datos adjuntos de archivos.
-
Haga clic con el botón secundario en la carpeta Business Objects del proyecto MySolution.Module y elija Agregar elemento | Clase... Especifique Reanudar.cs como el nuevo nombre de archivo y haga clic en Agregar.
-
Reemplace la declaración de clase generada por el código siguiente:
using DevExpress.Persistent.Base; using DevExpress.Persistent.BaseImpl; using DevExpress.Xpo; using MySolution.Module.BusinessObjects; namespace MySolution.Module.BusinessObjects { [DefaultClassOptions] [ImageName("BO_Resume")] public class Resume : BaseObject { public Resume(Session session) : base(session) {} private Contact contact; [Association("Contact-Resumes")] public Contact Contact { get { return contact; } set { SetPropertyValue(nameof(Contact), ref contact, value); } } [Aggregated, Association("Resume-PortfolioFileData")] public XPCollection<PortfolioFileData> Portfolio { get { return GetCollection<PortfolioFileData>(nameof(Portfolio)); } } } }
-
Agregue la propiedad a la clase:
Resume``Contact
namespace MySolution.Module.BusinessObjects { [DefaultClassOptions] public class Contact : Person { // ... [Association("Contact-Resumes")] public XPCollection<Resume> Resumes { get { return GetCollection<Resume>(nameof(Resumes)); } } } }
-
Agregue otra clase al proyecto MySolution.Module y asígnele el nombre PortfolioFileData. Reemplace la declaración de clase generada por el código siguiente:
using DevExpress.Persistent.BaseImpl; using DevExpress.Xpo; namespace MySolution.Module.BusinessObjects { public class PortfolioFileData : FileAttachmentBase { public PortfolioFileData(Session session) : base(session) { } private Resume resume; [Association("Resume-PortfolioFileData")] public Resume Resume { get { return resume; } set { SetPropertyValue(nameof(Resume), ref resume, value); } } public override void AfterConstruction() { base.AfterConstruction(); documentType = DocumentType.Unknown; } private DocumentType documentType; public DocumentType DocumentType { get { return documentType; } set { SetPropertyValue(nameof(DocumentType), ref documentType, value); } } } public enum DocumentType { SourceCode = 1, Tests = 2, Documentation = 3, Diagrams = 4, ScreenShots = 5, Unknown = 6 }; }
En esta lección, derivamos de la clase en la aplicación basada en XPO y de la clase en la aplicación basada en EF Core. y son clases de Business Class Library. Estas clases pueden almacenar archivos en la base de datos. Para obtener más información acerca de las propiedades de datos adjuntos de archivo, consulte los siguientes temas: Propiedades de datos adjuntos de archivo en XPO/EF Core.
PortfolioFileData``FileAttachmentBase``FileAttachment``FileAttachmentBase``FileAttachment
En la aplicación basada en XPO, inicializamos la propiedad en el método AfterConstruction() al que se llama después de la creación del objeto correspondiente. Consulte el tema siguiente para obtener más información: Cómo: Inicializar objetos de negocio con valores de propiedad predeterminados en XPO.
PortfolioFileData.DocumentType
-
En aplicaciones basadas en EF Core, agregue el atributo Required a la propiedad de la clase.
Resume``PortfolioFileData
using DevExpress.Persistent.BaseImpl.EF; namespace MySolution.Module.BusinessObjects { [ImageName("BO_FileAttachment")] public class PortfolioFileData : FileAttachment { public PortfolioFileData() : base() { DocumentType = DocumentType.Unknown; } //.. [Required] public virtual Resume Resume { get; set; } //... } } //... }
Las clases y están conectadas con una relación de Uno a Muchos. Para obtener más información sobre cómo crear una relación de uno a varios entre objetos de negocio, consulte los siguientes temas: Establecer una relación de uno a varios (XPO/EF Core).
Resume
PortfolioFileData
En la aplicación basada en EF Core, una eliminación de un objeto maestro no elimina los objetos relacionados. En esta lección, usamos el atributo Required para configurar las asociaciones entre clases. De esta manera, puede eliminar los objetos a los que se hace referencia con el objeto maestro y evitar la violación de la integridad.
Como alternativa, puede usar la API Fluent y especificar el método OnDelete para la relación - como se describe en el tema siguiente: El método OnDelete de la API Fluent.
Portfolio``Resume
-
Agregue el atributo RuleRequiredFieldAttribute a la propiedad para implementar la validación del valor de la propiedad:
Resume
using DevExpress.Persistent.BaseImpl; using DevExpress.Xpo; namespace MySolution.Module.BusinessObjects { public class PortfolioFileData : FileAttachmentBase { public PortfolioFileData(Session session) : base(session) { } private Resume resume; [Association("Resume-PortfolioFileData")] [RuleRequiredField(DefaultContexts.Save)] public Resume Resume { get { return resume; } set { SetPropertyValue(nameof(Resume), ref resume, value); } } //... } //.. }
Para obtener información adicional sobre la validación, consulte el artículo siguiente: Validación (evitar errores de datos).
-
En aplicaciones basadas en EF Core, abra el archivo MySolution.Module.BusinessObjects\MySolutionDbContext.cs y agregue las propiedades de , y tipos a :
Resume``PortfolioFileData``FileAttachments``DbContext
public class MySolutionDbContext : DbContext { //... public DbSet<Resume> Resumes { get; set; } public DbSet<PortfolioFileData> PortfolioFileData { get; set; } public DbSet<FileAttachment> FileAttachments { get; set; } }
-
Agregue una migración y actualice la base de datos. Consulte la siguiente sección para obtener más información: Usar un DBMS: Migraciones de configuración.
-
Ejecute la aplicación. Abra la vista Lista de reanudación y cree un nuevo objeto Reanudar. Rellene el campo Contacto y agregue un nuevo objeto Datos de archivo de cartera. En la ventana Datos de archivo de cartera, especifique el Tipo de documento y seleccione el archivo que desea adjuntar.
Los usuarios pueden hacer clic en el vínculo del archivo para descargar el archivo de currículum.
Para obtener un archivo almacenado dentro de un objeto en código, utilice el método de su propiedad.PortfolioFileData``IFileData.SaveToStream``File