Visto che abbiamo creato una mini applicazione funzionante, voglio fare un esperimento. Nel Nuovo framework .Net Core versione 3.0, che potete scaricare qui sono stati inseriti sia WPF che Windows Forms, che sono stati condivisi, nella versione per Windows, su GitHub come progetti open source. Sarebbe davvero una cosa bellissima poter creare un applicazione Desktop che funzionasse su tutti i sistemi operativi. Pertanto spero che qualcuno ne faccia un Fork per Linux o per Mac.
Detto questo, voglio provare a creare un applicazione WPF con .Net Core 3.0 e convertire al suo interno l’applicazione WpfGridColors della serie precedente.
Per farlo inizio creando da zero un applicazione WPF .Net Core e poi vediamo cosa succede.
Aprendo il nuovo Visual Studio 2019 in preview che potete scaricare qui e installare attivando lo sviluppo con .Net Core 3.0 vi verranno installati anche i Template WPF e Windows Forms per il suddetto framework. Qui sotto la creazione della mia Applicazione. Se non lo trovaste fra i progetti recenti, potete ricercarli usando la comoda finestra di ricerca e le combobox per selezionare linguaggio, piattaforme e tipo progetto così da filtrare solo quel che ci interessa.
Per generare l’applicazione selezionato il Template WPF App (.Net Core) e premo il tasto Next.
Inserisco il nome del progetto (Automaticamente viene chiamato con lo stesso nome anche la soluzione, volendo posso darle un nome diverso) Nell’installazione automatica, la Location, ovvero la cartella dove sarà creata la cartella della solution, è situata nella cartella Documents dell’utente, io usualmente ho un disco (o una partizione) dedicata ai progetti di sviluppo su cui metto i progetti. Pertanto come in questo caso ho cambiato la cartella per selezionare quella dei miei progetti didattici.
L’aspetto dell’Interfaccia di sviluppo di Visual Studio 2019, diviene uguale a quella della Versione 2017 e tutte le precedenti, e nel Solution Explorer troviamo quasi tutto quello che ci aspettiamo in una Applicazione WPF, fatto salvo qualche piccolo cambiamento.
Abbiamo una soluzione, un progetto, App.xaml e MainWindow.xaml. Ciò che cambia è che non c’è il nodo Properties e il nodo References, però c’è un nodo che si chiama Dependencies.
Questo ovviamente è quello che ha terrorizzato me e presumo chi come me dal 2003 ad oggi ha creato progetti .Net. Però mettiamo da parte la paura e cerchiamo dove è sparita la prima cosa che io modifico in qualsiasi progetto ovvero il nome dell’assembly e il Root Namespace.
Nei normali progetti .Net, oltre al nodo sul Solution Explorer, si può accedere alle Property della Solution e a quelle del progetto facendo un Tasto Destro sul nodo della solution e selezionando l’opzione Properties.
Pertanto ci proviamo?
L’opzione di menu è ancora li, pertanto provo a premerla e vedo cosa succede. Notate anche che c’è uno shortcut Alt+Enter possiamo annotarcelo.
Premendo l’opzione di menu appare quello che mi aspettavo, quindi tiriamo un sospiro di sollievo e annotiamo Alt+Enter come modo per accedere alle property del progetto. Credo possiamo verificare con sollievo che la pagina application è praticamente identica a quella del WPF full framework.
Pertanto Vi invito, come faccio sempre quando parlo di progetti nel mondo reale, a modificare il Default Namespace, inserendovi un Prefisso che identifica voi stessi o la vostra azienda, in modo da marcare le vostre classi come vostre proprie e soprattutto differenziarle dalle classi del Framework anche se magari vi verrà qualche nome uguale.
Nella versione didattica full framework non l’ho fatto, ma in questa versione lo farò, anche perché il codice non lo riscriverò, ma lo prenderò dalla vecchia applicazione. Quindi devo lavorare almeno un po’.
Ho inserito DNW come sigla DotNetWorker come prefisso al namespace di default, ho aggiunto un icona (è opportuno che i vostri programmi abbiano un icona personalizzata). E per la versione demo mi fermo qui.
Proseguiamo con la traslazione dell’applicazione. Considerato che ho deciso di importare il codice dal progetto fatto con il framework Full, vado a cancellare App.xaml e MainWindow.xaml.
Cancellando i 2 file di base dell’applicazione WPF ciò che vedete qui sopra è quel che resta. Andiamo perciò a prendere quello che avevamo nel progetto completo con il Full Framework, e trasferiamolo qui dentro. Prima di tutto App.Xaml.
Per aggiungere un file di classe da un progetto diverso usiamo il menu contestuale dal nodo di progetto, Add Existing Item e andiamo a cercare il file App.xaml dell’applicazione già scritta.
Come vedete, sulla window di ricerca file mi sono spostata sulla cartella che ospita il progetto WpfGridColors terminato nel post precedente questo e Visual Studio, per default mi mostra i files di tipo .cs ovvero le classi CSharp. Però in questo caso voglio importare App.xaml oltre ad App.xaml.cs quindi devo cambiare il tipo di file da importare. Lo faccio usando la combobox accanto alla Textbox File name:
Seleziono il tipo di file XAML e nella finestra appaiono i file di questo tipo. Seleziono App.xaml e premo invio e quel che troverò nella mia Solution .net Core è quanto mostrato di seguito.
In questo caso, Visual Studio sa che ogni file Xaml ha anche un file di codice collegato (xaml.cs) e quindi lo importa e correttamente lo aggancia come dipendente del file Xaml facendolo apparire nel sottolivello della Tree di progetto. Il codice contenuto nel file rimane invariato.
Prima di aggiungere anche MainWindow, andiamo a modificare il Namespace dei 2 file :
<Application x:Class="DNW.WpfGridColorscore.App"
Cambiamo il namespace di App.xaml in quello che abbiamo impostato come DefaultNamespace per il progetto .Net Core
namespace DNW.WpfGridColorsCore { public partial class App : Application { } }
Facciamo lo stesso con la parte di codice e quindi con App.xaml.cs.
Ora ripetiamo l’operazione per MainWindow.xaml. Siccome bisogna sempre migliorare il proprio codice, farò un paio di mini modifiche a MainWindow per prima cosa aggiungendo una cartella Windows e copiandolo nella cartella invece che sulla root di progetto.
Usiamo il menu contestuale dal nodo di progetto ed aggiungiamo la cartella Windows usando Add New Folder.
Poi ripetiamo l’importazione del file esistente posizionandoci sul Nodo Windows e selezionando dalla cartella del progetto WpfGridColors il file MainWindow.xaml.
Nella solution, sotto alla cartella Windows troveremo MainWindow.xaml e andiamo quindi a modificare anche il suo Namespace.
<Window x:Class="DNW.WpfGridColorsCore.Windows.MainWindow"
namespace DNW.WpfGridColorsCore.Windows { public partial class MainWindow : Window, INotifyPropertyChanged {
Non guardiamo agli errori, perché fino a che non finiremo di importare il resto delle classi e fare i necessari aggiustamenti, ci saranno molti errori.
Andiamo a generare il resto delle cartelle che abbiamo usato nel progetto di origine, quindi:
- Collections
- Converters
- Entities
- Helpers
- Images
In modo da preparare lo spazio per importare il resto delle classi e dei file accessori del progetto.
Quando vi posizionerete sul nodo di progetto ed aggiungerete le cartelle potrete notare come Visual Studio 2019 ci mostra il contenuto XML del file WpfGridColorsCore.csproj. Nella nuova filosofia di .net Core il progetto è un file gestito in modo più semplice e modificabile in modo diretto senza la necessità d fare un Unload per poterlo fare. Per ora noi ci limitiamo all’uso uguale a quello fatto fino ad oggi, però dare un occhiata a come cambia il file quando aggiungiamo file, classi e reference è certamente utile a capire come funziona.
Una volta create le cartelle importiamo le classi che vi vanno inserite dal progetto origine. utilizzando nuovamente Add Existing Item… posizionandoci sulla cartella pertinente.
Non riporto tutti gli screenshot per evitare un articolo chilometrico, ma riporto l’import delle 2 immagini perché ci sono 2 cose diverse da fare
Per prima cosa, quando selezioniamo la cartella Images, dobbiamo cambiare il tipo di file da importare.
Selezioniamo il tipo di file Image Files per visualizzare e selezionare le immagini. Possiamo selezionarle entrambe in una sola volta e premere Add.
Dopo averle importate è necessario selezionare ciascuna immagine e sulle property controllare che la Build Action sia Resource se non lo fosse modificarla in modo che il comportamento sia quello da noi atteso. Non so se si tratta di qualcosa dovuto al fatto che Visual Studio 2019 è ancora in Preview, ma entrambe erano configurate con l’opzione None. Pertanto controllate.
Dopo l’importazione di tutti i file, il solution explorer diventerà il seguente:
Tutti i file di progetto ora sono contenuti nel nuovo progetto .net Core. Andiamo quindi a modificare tutti i Namespace, faccio solo una lista per brevità:
- ColumnDataCollection: Dnw.WpfGridColorsCore.Collections
- DecimalAmountToColorConverter: Dnw.WpfGridColorsCore.Converters
- DecimalPercentToColorConverter: Dnw.WpfGridColorsCore.Converters
- TrendToImageConverter: Dnw.WpfGridColorsCore.Converters
- ColumnDataItem: Dnw.WpfGridColorsCore.Entities
- CustomerStats: Dnw.WpfGridColorsCore.Entities
- XmlHelper: Dnw.WpfGridColorsCore.Helpers
Le Immagini non hanno bisogno di namespace, ma come tutte le risorse assumeranno quello della cartella.
Oltre a cambiare i Namespace delle classi, ovviamente vanno modificati anche quelli degli using dove sono utilizzati, pertanto per non dimenticarne alcuno un metodo rapido è usare il Trova e Sostituisci a livello di progetto.
Se non lo avete mai usato si attiva con Ctrl+Shift+H per la sostituzione o Ctrl+Shift+F per la ricerca.
Questa finestra permette di cercare testo, sostituire testo sia in modo normale che con le regular expressions in tutti i file di una solution o di un progetto date un occhiata alle combobox per prendervi confidenza se siete nuovi di Visual Studio. Io mi sono limitata a indicare il vecchio Namespace, il nuovo Namespace, di guardare in tutta la Solution controllando Maiuscole e minuscole nei file di tipo cs e xaml. potete usare il Find per cercare e poi Replace per modificare o, se siete coraggiosi, il Replace All
Dopo questa operazione, rimangono ancora un po’ di errori, il principale è che mi sono dimenticata di importare ColumnChooserWindow pertanto, andiamo a ripetere l’operazione effettuata per MainWindow, posizionandoci sulla cartella Windows e usando Add Existing Item…
Importata questa Window il solution explorer diventa quello visto qui sopra. Ora andiamo nello xaml e nel .cs e cambiamo i namespace nel modo corretto.
Una volta fatto, rimarranno ancora alcuni errori proprio sui Namespace, perché le using all’interno di XAML vanno modificate di conseguenza vediamo come diventano le dichiarazioni dei namespace per le due Window:
<Window x:Class="DNW.WpfGridColorsCore.Windows.ColumnChooserWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:local="clr-namespace:DNW.WpfGridColorsCore" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="Selezione Visibilità colonne" Width="300" Height="450" ContentRendered="ColumnChooser_ContentRendered" mc:Ignorable="d">
<Window x:Class="DNW.WpfGridColorsCore.Windows.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:lconv="clr-namespace:DNW.WpfGridColorsCore.Converters" xmlns:local="clr-namespace:DNW.WpfGridColorsCore" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" Title="Statistica" Width="900" Height="450" ContentRendered="MainWindow_ContentRendered" mc:Ignorable="d">
Le dichiarazioni dei namespace lconv e local devono essere modificati in base al nuovo namespace importato. a questo punto, ricompilando l’applicazione tutto dovrebbe andare a posto. però se proviamo a lanciare l’applicazione otterremo un errore, esattamente questo:
L’errore ci dice che la risorsa MainWindow.xaml non è stata trovata. Perchè? Perchè mi sono dimenticata ancora una modifica.
<Application x:Class="DNW.WpfGridColorscore.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:DNW.WpfGridColorscore" StartupUri="Windows/MainWindow.xaml">
Siccome abbiamo spostato la MainWindow.xaml sulla cartella Windows, lo StartupUri all’interno di App.xaml va modificato di conseguenza. Fatto questo lanciando l’applicazione il risultato è paritetico a quanto effettuato nell’applicazione con il full framework.
Come vedete ho attivato tutte le colonne e ho spostato delle colonne ed ho ordinato i dati secondo la colonna Trend.
Credo che questa modalità sia la più semplice e sicura per trasformare una applicazione WPF full framework in una applicazione WPF .net Core, ovviamente se l’applicazione non fa uso di funzionalità non ancora presenti nella nuova versione.
Ovviamente, per una applicazione più complessa di questa è opportuno evitare di cambiare il namespace, così da dover lavorare un po’ di meno quando vi siano decine di classi.