Azioni del controllo

Ad ogni controllo possono essere aggiunte una o più azioni (denominate ContextAction).
Una volta aggiunte, le azioni sono visualizzate nell'apposito menù a destra del controllo:
 
Actions example
 
Questi sono di tipi di azione disponibili:
 
  • UpdateData: azione di aggiornamento dei dati del controllo
  • SetNavigation: azione di navigazione a un'altra sezione o item
  • SetRemoteAction: azione per l'esecuzione di codice personalizzato lato client
  • SetLocalAction: azione per l'esecuzione di codice personalizzato lato server
 
La classe Control mette a disposizione alcuni metodi basati su ContextActionService per aggiungere rapidamente una nuova azione al controllo.
 
Azione UpdateData
Il metodo aggiunge un'azione di aggiornamento dei dati nel controllo in modo da non dover ricaricare la pagine se la sorgente dati è stata modificata dopo l'apertura del form. Il codice seguente aggiunge l'opzione di aggiornamento per il controllo predefinito CheckBoxList.
 
using System;
using System.Threading.Tasks;

namespace DataWeb.Data.Controls
{
    public class CheckBoxList : ControlBase
    {
        public CheckBoxList(Form form, IServiceProvider serviceProvider) : base(form, serviceProvider)
        {
        }

        public override Task InitAsync()
        {
            AddActionUpdateData();

            return Task.CompletedTask;
        }
    }
}
 
Va segnalato che tutti i controlli predefiniti che gestiscono liste di valori (CheckBoxList, ListBox, RadioButtonList, DropDownList, ecc.) hanno già impostata questa azione.
 
Azione SetNavigation
Il metodo aggiunge un'azione che permette all'utente di aprire una sezione o un item rapidamente. Ad esempio, dato un DropDownList con un elenco di categorie, si vuole permettere all'utente di aggiungerne una nuova, modificare quella selezionata o aprire la sezione dedicata.
DataWeb salverà automaticamente i dati dell'item prima di impostare la navigazione. La navigazione viene aggiunta a quella esistente ovvero quando l'utente chiude la categoria viene riportato all'item di partenza rendendo l'esperienza più piacevole.
 
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
using DataWeb.Structure;
using DataWeb.Identity;
using DataWeb.Data;
using DataWeb.Data.Controls;
using DataWeb.WebApp.Infrastructure;
using Microsoft.Extensions.Localization;

namespace DataWeb.WebApp.DataWeb.Data.Controls
{
    public class Product_CategoryName :  DropDownList
    {
        private readonly CategoryRepository categoryRepository;
        private readonly IStringLocalizer localizer;

        public Product_CategoryName(Form form, IServiceProvider serviceProvider) : base(form, serviceProvider)
        {
            categoryRepository = serviceProvider.GetService<CategoryRepository>();
            localizer = serviceProvider.GetService<IStringLocalizer>();
        }

        public override async Task InitAsync()
        {
            await base.InitAsync();

            AddActionSetNavigation(localizer["DataWeb.Form.ControlAction_EditSelected"], new List<Action.Step>()
            {
                new Action.Step{ IdMaster = StructureDefinition.RootIdMaster, SectionName = AppStructureDefinition.SectionDemoCategories, IsHidden = true },
                new Action.Step{ IdMaster = "{ {IdMaster} }", SectionName = AppStructureDefinition.SectionDemoCategoryData }
            });

            AddActionSetNavigation(localizer["DataWeb.Form.ControlAction_New"], new List<Action.Step>()
            {
                new Action.Step{ IdMaster = StructureDefinition.RootIdMaster, SectionName = AppStructureDefinition.SectionDemoCategories, IsHidden = true },
                new Action.Step{ IdMaster = StructureDefinition.VoidIdMaster, SectionName = AppStructureDefinition.SectionDemoCategoryData }
            });

            AddActionSetNavigation(localizer["DataWeb.Form.ControlAction_OpenSection"], new List<Action.Step>()
            {
                new Action.Step{ IdMaster = StructureDefinition.RootIdMaster, SectionName = AppStructureDefinition.SectionDemoCategories }
            });
        }
    }
}
 
Al metodo deve essere fornito il titolo dell'azione (nell'esempio localizzato con Localizer) e i nuovi step di navigazione. Il parametro opzionale currentStep permette di spostarsi iin una sezione adiacente a quella attuale.
 
Azione SetLocalAction
Il metodo aggiunge un'azione che permette all'utente di eseguire del codice client posizionato nel componente Vue.js personalizzato.
Ad esempio nel controllo User_AccountNewsletter troviamo l'aggiunta dell'azione locale (client) Edit:
 
using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using DataWeb.Identity;
using DataWeb.Structure;
using DataWeb.Validation;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;

namespace DataWeb.Data.Controls
{
    public class User_AccountNewsletter(Form form, IServiceProvider serviceProvider) : Control(form, serviceProvider)
    {
        private readonly IStringLocalizer localizer = serviceProvider.GetService<IStringLocalizer>();

        public override Task InitAsync(CancellationToken cancellationToken = default)
        {
            AddActionSetLocalAction(localizer["DataWeb.Form.AccountNewsletter_Edit"], "Edit", ContextActionType.Edit);

            return Task.CompletedTask;
        }

        public override Task<List<ValidationError>>ValidateAsync(object value, List<Form.ProvidedValue> providedValues, Dictionary<string, object> sectionData, IUser user, string itemId = null, NavigationContext navigationContext = null, CancellationToken cancellationToken = default)
        {
            var errors = new List<ValidationError>();

            return Task.FromResult(errors);
        }

        public override Task<bool> IsUpdateDataAsync(object value, List<Form.ProvidedValue> providedValues, Dictionary<string, object> sectionData, IUser user, string itemId = null, NavigationContext navigationContext = null, CancellationToken cancellationToken = default)
        {
            return Task.FromResult(false);
        }
    }
}
 
E nel codice del componente Vue.js intecettiamo la selezione dell'azione Edit:
 
    public startLocalAction(action: any) {
        switch (action.name) {
            case "Edit":
                this.edit();
                break;
        }
    }
 
Azione SetRemoteAction
Il metodo aggiunge un'azione che verrà eseguita lato server, da un metodo C# dedicato.
Qui ad esempio stiamo impostando un'azione di notifica tramite email e il cambio stato di un prodotto:
 
using System;
using System.Threading.Tasks;
using System.Threading;
using System.Collections.Generic;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Localization;
using DataWeb.Structure;
using DataWeb.Identity;
using DataWeb.Data;
using DataWeb.Data.Controls;
using DataWeb.Web.App.Infrastructure;

namespace DataWeb.Web.App.DataWeb.Data.Controls
{
    public class Product_ActionListAreaName(Form form, IServiceProvider serviceProvider) :  ActionList(form, serviceProvider)
    {
        private readonly IStringLocalizer localizer = serviceProvider.GetService<IStringLocalizer>();
        private readonly ProductStore productStore = serviceProvider.GetService<ProductStore>();

        public override async Task InitAsync(CancellationToken cancellationToken = default)
        {
            await base.InitAsync(cancellationToken);

            AddActionSetRemoteAction("Notify status", "NotifyStatus", ContextActionType.Notification, isConfirmRequired: true, isSaveItemBeforeProcess: true, isReloadAfterProcess: true);

            AddActionSetRemoteAction("Set product status", "SetProductStatus", ContextActionType.Dialog, dialogFormName: "Form_ActionProductStatus", isConfirmRequired: true, isSaveItemBeforeProcess: true, isReloadAfterProcess: true);
        }

        public override async Task<ContextAction.Result> ProcessActionAsync(ContextAction action, IUser user, string itemId = null, object value = null, List<Form.ProvidedValue> controlValues = null, NavigationContext navigationContext = null, CancellationToken cancellationToken = default)
        {
            var result = await base.ProcessActionAsync(action, user, itemId, value, controlValues, navigationContext, cancellationToken);
            if (!result.IsValid)
            {
                return result;
            }

            switch (action.Name)
            {
                case "NotifyStatus":
                    result = await NotifyStatus(itemId);
                    break;
                case "SetProductStatus":
                    result = await NotifyStatus(itemId);
                    break;
            }

            return result;
        }

        public async Task<ContextAction.Result> NotifyStatus(string itemId = null)
        {
            await productStore.UpdateDescriptionAsync(itemId);

            var result = new ContextAction.Result { IsValid = true };
            return result;
        }
    }
}
 
Nella creazione di un'azione remota lato server è possibile personalizzare il flusso di esecuzione con questi parametri:
 
  • IsConfirmRequired: se attivo richiede una conferma tramite dialog modale prima di eseguire l'azione
  • IsSaveItemBeforeProcess: se attivo salva i dati del form corrente prima di eseguire l'azione
  • DialogFormName: permette di specificare il nome del form che comparità nella dialog modale per raccogliere valori aggiuntivi per l'azione
  • IsReloadAfterProcess: se attivo ricarica i dati nel form corrente aggiornandone il contenuto
  • IsDownloadResult: indica al browser di scaricare il risultato dell'azione come file (ad esempio in caso di generazione di un report).