Press "Enter" to skip to content

Datagrid WPF standard un caso d’uso reale (parte 2)

Creazione della collection che fornirà l’ItemsSource della Datagrid

Proseguiamo l’articolo precedente e ci spostiamo all’interno della classe MainWindow.xaml.cs generata automaticamente dal Template di progetto dove inizieremo a fare le prime modifiche per produrre i dati da visualizzare sulla nostra datagrid.

Modifiche a MainWindow.xaml.cs

Prima di ogni cosa, anche in MainWindow andiamo ad implementare l’interfaccia INotifyPropertyChanged, così da poter usare il codice scritto nella window come ViewModel per la finestra stessa (MVVM molto semplificato).

using System.ComponentModel;

Fra le clausole using della classe, aggiungiamo il namespace che contiene l’interfaccia INotifyPropertyChanged

public partial class MainWindow : WindowINotifyPropertyChanged

Aggiungiamo l’interfaccia alla dichiarazione della classe e all’interno del codice della stessa copiamo il codice per l’implementazione dell’evento OnPropertyChanged esattamente uguale a quello che trovate nella classe CustomerStats.

 

public event PropertyChangedEventHandler PropertyChanged;
 
protected virtual void OnPropertyChanged(string propertyName)
{
	if (PropertyChanged != null)
		PropertyChanged(thisnew PropertyChangedEventArgs(propertyName));
}

Fatto questo, andiamo a modificare il costruttore della classe nel seguente modo:

public MainWindow()
{
	InitializeComponent();
	DataContext = this;
	Statistics = new ObservableCollection<CustomerStats>();
}

Nella classe generata automaticamente, il costruttore della classe contiene solo la chiamata ad InitializeComponent, metodo che processa il codice automaticamente generato a partire dalla parte XAML della finestra e istanzia i componenti in esso definiti.

A questo codice, aggiungiamo due righe semplici ma fondamentali, soprattutto la prima, che con il comando: DataContext = this; indica a WPF che questa classe è il ViewModel di se stessa ovvero, in parole semplici (spero) tutti i dati collegati ai controlli inseriti nello xaml si trovano in questa classe che fornisce appunto il Data Context (contesto dati) a tutta la Window.

Se non sapete cos’è il DataContext, spero che proseguendo lungo questo e i prossimi articoli, possiate comprenderlo sufficientemente bene.

La seconda riga aggiunta, Istanzia la Collection (vuota) dei dati statistici che utilizzeremo come sorgente dati (ItemsSource) della DataGrid che metteremo nella Window.

Definiamo anche la Property Statistics prima di modificare il codice del costruttore.

public const string FLD_Statistics = "Statistics";

private ObservableCollection<CustomerStatsmStatistics;
 
public ObservableCollection<CustomerStatsStatistics
{
	get
	{
		return mStatistics;
	}
	private set
	{
		mStatistics = value;
		OnPropertyChanged(FLD_Statistics);
	}
}

Per definire la nostra collezione, creiamo una property di tipo ObservableCollection, questo tipo di collection aggiunge la gestione automatica della generazione degli eventi quando la collection viene modificata, ovvero la collection informa la User Interface del fatto che un elemento è stato aggiunto o tolto permettendo a WPF di modificare automaticamente la visualizzazione.

Creata la Property, passiamo al metodo che carica i dati al suo interno.

private void LoadData()
{
	Statistics.Clear();
	CustomerStats stats = new CustomerStats()
	{
		CustomerName = "Rossi Spa",
		SalesTotal = 23670.16m,
		Year="2018",
		BudgetTotal = 17920.17m
	};
	Statistics.Add(stats);
 
       ...
 
	stats = new CustomerStats()
	{
		CustomerName = "Stark industries International",
		SalesTotal = 98620.65m,
		Year = "2017",
		BudgetTotal = 160000m
	};
	Statistics.Add(stats);
 
	var years = (from s in Statistics orderby s.Year select new { s.Year }).Distinct();
	foreach (var year in years)
	{
		UpdatePercentages(Statistics.Where(x=>x.Year==year.Year).ToList());
	}
 
	
}

Creiamo un metodo che genera una lista di dati a caso per 2 anni di statistiche (2017 e 2018) per brevità, ho lasciato solo il primo e l’ultimo degli oggetti “riga” generati e aggiunti alla collection, ma nel codice a corredo ne troverete una ventina.

Il codice per inserire gli oggetti nella lista è semplice:

  1. Genero un istanza della classe CustomerStats
  2. Riempio le proprietà con i dati di test
  3. Aggiungo la classe così generata alla lista statistiche

Una volta fatto questo, faccio una cosa piuttosto complicata ma molto utile.

var years = (from s in Statistics orderby s.Year select new { s.Year }).Distinct();

Se non avete mai visto una query LINK quella scritta nella riga precedente è una Query effettuata sulla collection Statistics per richiedere di ricevere una lista dei valori Distinct (tutti i valori univoci) all’interno del campo Year delle righe della collection. Questo ci permette di estrarre i 2 anni di statistica ed effettuare poi i calcoli delle percentuali di incidenza dei fatturati sui totali relativi a ciascun anno.

 

foreach (var year in years)
{
	UpdatePercentages(Statistics.Where(x=>x.Year==year.Year).ToList());
}

Questa porzione del codice, chiama il metodo (che vedremo subito) che ricalcola le percentuali di incidenza sulle vendite per ciascuno degli anni di statistica. La porzione di codice che inizia per Statistics.Where è un altra query LINQ che richiede alla Collection Statistics tutti gli elementi che contengono nella property Year il valore contenuto nell’oggettino a noi restituito dalla query Distinct degli anni. In questo caso, years contiene 2017 e 2018.

private void UpdatePercentages(List<CustomerStatsstatList)
{
	decimal totSales = statList.Sum(x => x.SalesTotal);
	decimal totBudget = statList.Sum(x => x.BudgetTotal);
 
	foreach (CustomerStats stat in statList)
	{
		stat.PercentSales = Math.Round((100 * stat.SalesTotal / totSales), 2);
		stat.PercentBudget = Math.Round((100 * stat.BudgetTotal / totBudget),2);
	}
}

Questo metodo, calcola l’incidenza in percentuale del fatturato previsto (budget) e di quello effettivo sul totale fatturato previsto o fatturato effettivo. pertanto le prime 2 righe usano la funzione Sum di LINQ per calcolare il totale fatturato effettivo ed il totale fatturato previsto.

Il ciclo successivo, usa una proporzione per calcolare il valore percentuale del fatturato di un singolo cliente sul totale effettivo ovvero

Totale Fatturato : 100 = Fatturato Cliente : x

Arrotondiamo a 2 cifre per avere dei numeri potabili. (Math.Round è una funzione della libreria matematica di .Net dove trovate tutte le funzioni matematiche e statistiche di base).

Con queste operazioni abbiamo finito di creare i nostri dati, quindi possiamo passare allo step successivo, che sarà la creazione dell’interfaccia per visualizzare i dati con la DataGrid per poi passare al succo di tutto questo, ovvero come dare valore aggiunto all’esperienza utente.