Nuovo modulo
LA creazione di una nuova vista comincia con la creazione di un nuovo modulo POS. In Visual Studio bisogna selezionare nuovo progetto WPF Custom Control Library. Questo tipo di progetto genera automaticamente la struttura necessaria e consente di aggiungere nuovi elementi. All’inizio il progetto sarà composto dalla cartella Themes in cui si troverà il file Generic.xaml e del file CustomControl1.cs. I file possono essere eliminati.
Il passo successivo consiste nel creare la classe Module.cs che sarà responsabile per la registrazione del modulo nell’applicazione POS. Questa classe deve ereditare dalla classe di base ModuleBase (Comarch.POS.Presentation.Core) e appropriatamente implementare il metodo Initialize. All’interno di questo metodo registriamo i nostri servizi, viste e viewmodels, registrare i pulsanti del menu principale POS, registrare i nostri campi di controllo, gestire la visibilità delle proprietà dei campi di controllo nella gestione dell’interfaccia, attaccare (estendere) i contenitori e datagrid esistenti nel sistema.
Perché l’utente abbia la possibilità di gestire la vista durante il funzionamento dell’applicazione POS, nella cartella Themes bisogna aggiungere un nuovo elemento del tipo Resource Dictionary (cliccare con il tasto destro del mouse sulla cartella Themes e poi, in ordine: Add, Resource Dictionary…). Assegnargli il nome ModernUI.xaml e salvarlo. In questo file saranno definite le proprietà predefinite per gli elementi gestiti dell’interfaccia (viste, campi di controllo). Le informazioni più dettagliate si trovano nell’articolo <<Gestione della vista e dei suoi elementi>>. Alla fine bisogna registrare la risorsa. Questo passo va eseguito nel costruttore della classe Module tramite l’aggiunta della seguente riga:
LayoutService.RegisterResources(typeof(Module));
(LayoutService è una classe statistica che si trova nell’area Comarch.POS.Presentation.Core.Service).
Creazione delle viste
La creazione di una nuova vista comincia con la creazione della cartella Views in cui verranno mantenute tutte le viste del progetto e della cartella ViewModels per i viewmodels. Poi, nella cartella Views, bisogna aggiungere un nuovo elemento del tipo User Control (WPF), denominato, per esempio, OrdersView.xaml.
Il passo successivo consiste nel cambiare il tipo UserControl in View nell’area Comarch.POS.Presentation.Core.
<core:View x:Class="Comarch.POS.Presentation.Sales.Views.OrdersView"
xmlns:core="clr-namespace:Comarch.POS.Presentation.Core;assembly=Comarch.POS.Presentation.Core"
In code-behind bisogna eliminare l’ereditarietà dal UserControl e implementare l’interfaccia richiesta View.
LA proprietà Header è la stringa visualizzata nella sezione della testata dell’applicazione. La proprietà deve essere impostata soltanto per le viste che saranno aperte come viste di base perché solo tali viste hanno la presentazione della testata. Negli altri casi (cioè per la vista modale e per il messaggio) basta impostare String.Empty. Esiste anche la possibilità di creare la propria testata della sezione con qualsiasi contenuto. Più informazioni si possono trovare nella sezione <<Aggiunta della propria testata>>.
La proprietà HeaderLayoutId dovrebbe invece contenere il nome unico per l’ID layout id che è indispensabile per il corretto funzionamento della gestione della vista da parte dell’utente POS. Se la vista non deve essere possibile da gestire, si può impostare la proprietà come String.Empty. Per gli scopi di questa documentazione specifichiamo il valore come “OrdersViewId”.
Il costruttore di base richiede il trasferimento dell’oggetto del tipo IviewModel e per questo motivo adesso passiamo alla creazione del viewmodel. Prima, nella cartella ViewModels, bisogna creare la cartella denominata Orders. Poi, all’interno della cartella bisogna aggiungere la nuova classe OrdersViewModel e l’interfaccia IOrdersViewModel. L’interfaccia dovrebbe essere pubblica ed ereditare da IViewModel. Anche la classe OrdersViewModel deve essere pubblica e implementare la classi di base ViewModelBase e l’interfaccia IOrdersViewModel.
Visto che si eredita da ViewModelBase, bisogna implementare il metodo IsTarget. Il metodo viene chiamato durante la navigazione e consente all’istanza del viewmodel di verificare se proprio essa dovrebbe essere attivata o no (informazioni più dettagliate: <<Navigazione tra le viste>>); per allora impostiamo la restituzione di true.
In aggiunta, se la vista deve essere possibile da gestire dall’utente POS, bisogna aggiungere un’altra classe viewmodel denominata DesignOrdersViewModel che erediterà da DesignViewModelBase e implementare l’interfaccia IOrdersViewModel. L’intera struttura viene presentata nel disegno accanto.
Adesso bisogna tornare al code-behind della classe OrdersView (file OrdersView.xaml.cs) e parametrizzare il costruttore perché assumi il parametro del tipo IOrdersViewModel denominato viewModel (attenzione: questo nome è importante, il parametro deve chiamarsi proprio così). Poi completare il costruttore di base, trasferendogli la variabile viewModel.
L’ultimo passo consiste nel registrare la nuova vista. Il processo è descritto nel capitolo Registrazione delle viste per la navigazione e per la gestione dell’aspetto.
Pronto modello di creazione di un modulo con vista vuota è disponibile nell’esempio <<Modulo semplice con nuova vista vuota>>.
Aggiunta della propria testata
Per ogni vista di base è possibile impostare il testo della testata che verrà presentato nella parte superiore dell’applicazione POS. Per impostazione predefinita, è solo possibile collocarci una stringa di caratteri definita nella proprietà Header della vista. Nel caso in cui sia necessario mettere nella testata una struttura più complessa, è possibile creare la propria vista di testata (custom header).
La definizione della propria testa comincia con l’aggiunta della cartella con la vista del nuovo elemento User Control (WPF). Per migliorare la visibilità l’elemento avrà lo stesso nome della vista, ma con il prefisso Header (per la vista OrdersView il nome sarà OrdersViewHeader).
Alla fine bisogna ritornare a code-behind della vista OrdersView e impostare nel costruttore la proprietà CustomHeaderType sul tipo della nostra testata personalizzata. Alla vista della testata viene automaticamente assegnato il DataContext che indicherà ViewModel della vista. Nel nostro caso questo sarà OrdersViewModel. Grazie a tutto ciò, nella nostra testata sarà possibile utilizzare il binding direttamente verso la proprietà sul viewmodel della vista.
public partial class OrdersView
{
public OrdersView(IOrdersViewModel viewModel) : base(viewModel)
{
CustomHeaderType = typeof (OrdersViewHeader);
InitializeComponent();
}
…
…
Registrazione delle viste per la navigazione e gestione dell’aspetto
Dopo la creazione della vista (cioè l’implementazione corretta della logica di funzionamento in view-model e dell’UI in xaml) bisogna registrare la vista perché essa possa funzionare. Per farlo apriamo la classe Module creata durante la creazione del progetto (vedi: <<Nuovo modulo>>). Nel metodo Initialize aggiungiamo le seguenti righe:
Register<IOrderViewModel, OrderViewModel>();RegisterViews(new ViewStructure<OrdersView, DesignOrdersViewModel>("OrdersView", Resources.ResourceManager);
La prima riga registra il viewmodel nel contenitore, grazie a ciò nel costruttore della vista viene automaticamente inserita l’istanza dell’interfaccia IOrdersViewModel.
Il secondo metodo consente di registrare la vista nella modalità di gestione della sua interfaccia da parte dell’utente POS durante il funzionamento dell’applicazione. Grazie a ciò, dopo l’apertura della vista di gestione dell’interfaccia, nell’elenco delle viste l’utente vedrà la nostra vista. Potrà anche aprirlo per la modifica e cambiare l’aspetto di tutti gli elementi che definiremo come possibili da gestire (più informazioni su quello come farlo si trovano nel’articolo <<Gestione della vista e dei suoi elementi>>. Il metodo richiede il trasferimento di due parametri diversi: Il primo metodo è il nome della chiave nelle risorse, invece il secondo è l’istanza del manager delle risorse. Questi parametri permettono di presentare il nome della vista nell’albero delle viste nella gestione delle viste dell’applicazione POS.
Alternativamente, se non vogliamo registrare la vista nella modalità di gestione dell’interfaccia, dobbiamo utilizzare il metodo RegisterForNavigation<TView >() invece di RegisterViews.
RegisterForNavigation<OrdersView>();
Aggiunta della vista al menu principale
Ogni vista può essere aggiunta al menu principale sotto forma di una piastrella (TileButton) per rendere possibile l’apertura della vista nella modalità di base. Dopo l’aggiunta della vista al menu principale questa vista verrà automaticamente aggiunta anche all’estendibile menu laterale che può essere aperto dal livello di qualsiasi vista di base.
Per aggiungere la vista creata prima sotto forma di una piastrella al menu bisogna, nel metodo Initialize della classe Module registrare la vista con l’utilizzo del metodo RegisterMenuTile<TView>, dove TView è il nome della classe della vista. I parametri di richiamo sono invece, in ordine, il nome della chiave nelle risorse a il manager della risorse. Opzionalmente è anche possibile definire il delegato canExecute. In caso di restituzione del false la piastrella sarà grigia e inattiva. È anche possibile indicare il delegato per le azioni che vanno eseguite prima dell’apertura della vista e/o definire le autorizzazioni che saranno necessarie per aprire la vista insieme alla chiave nelle risorse dove sarà salvato il messaggio che apparirà nella finestra modale di estensione delle autorizzazioni per i casi in cui le autorizzazioni non saranno soddisfatte (più informazioni sulle autorizzazioni: <<Verifica delle autorizzazioni>>). Per gli scopi di questo esempio registriamo la vista precedentemente creata, cioè OrdersView.
RegisterMenuTile<OrdersView>("OrdersView", Resources.ResourceManager);
Dopo la registrazione della vista nel menu principale sarà possibile aprirla tramite la piastrella adeguata visibile nel menu principale. Per impostazione predefinita la piastrella sarà così come è stata definita nella configurazione dell’interfaccia POS. Per cambiare le sue proprietà visuali bisogna aggiungere le immissioni adeguate nel file ModernUI.xaml che si trova nella cartella Themes. Per esempio, per impostare un nuovo colore predefinito per la nostra nuova piastrella che apre la vista OrdersView, bisogna aggiungere la seguente inserzione:
<SolidColorBrush x:Key="OrdersView.Default.Background" Color="Red" />
Ogni chiave in MordernUI avrà il formato seguente:
[LayoutId o Nome del tipo del campo di controllo].Default.[Nome della proprietà]
Invece l’intera definizione sarà come segue:
<[Nome del tipo della proprietà] x:Key=”[chiave secondo il suddetto formato]” [attributi]>[valore]</[Nome del tipo della proprietà>
Gli attributi e il valore non sono necessari e dipendono strettamente dal tipo della proprietà in questione.
Il LayoutId per la piastrella della vista OrdersView viene definito nel primo parametro del metodo RegisterMenuTile. Nel nostro caso il LayoutId utilizzato nella chiave che definisce il colore della piastrella è OrdersView, perché tale valore è stato impostato prima durante il richiamo del metodo che registra la vista sotto forma della piastrella nel menu principale. Le proprietà, supportate dalla gestione dell’interfaccia, dipendono dal tipo del campo di controllo. Per le piastrelle questo è il campo di controllo TileButton. L’elenco delle proprietà supportate per particolari campi di controllo può essere trovato qui: <<Elenco delle proprietà supportate>>
Inserzione del modulo nell’applicazione POS
L’ultima tappa, dopo la compilazione del modulo creato, consiste nell’avviarlo nell’ambiente di destinazione, cioè nell’applicazione POS. Per farlo, bisogna copiare il modello costruito sotto forma di una libreria (o librerie) nella directory di installazione dell’applicazione POS. Poi aprire per la modifica il file POS.exe.config e trovarci la sezione <modules> e aggiungere il nuovo modulo alla fine della sezione secondo il modello:
<module assemblyFile=”[nome_modulo].dll” moduleType=”[namespace_della_classe_module].Module, [namespace_classe_module]” moduleName=”[ nome_modulo]” />
Nel caso in cui ci siano più librerie, registriamo soltanto quelle che hanno la classe Module implementata.