Può capitare di dover mostrare un risultato non immediatamente disponibile per la lettura, perché, ad esempio, il suo valore dipende da altri parametri e deve quindi essere calcolato. A tal fine, vogliamo mostrare un messaggio all’utente per indicare che l’applicazione è in esecuzione e che non è in una fase di stallo, qualcosa di simile quando utilizziamo un UpdateProgress dell’Ajax Control Toolkit (o corrispondenti soluzioni custom) nelle nostre pagine Web. In WPF, possiamo utilizzare il PriorityBiding per fare qualcosa di simile (ma non solo). Il PriorityBinding permette di associare ad una proprietà di un elemento, un elenco di associazioni (invece di una singola associazione dati come nel “normale” Binding). Tra le associazioni, viene considerata la prima che restituisce correttamente un valore: ovvero se il Path del Binding viene risolto correttamente, se il valore restituito da un Converter è valido (sempre che ne venga utilizzato uno) o se il valore è valido per la proprietà di destinazione. Supponiamo di avere una classe Data come la seguente:
1: public class Data : INotifyPropertyChanged
2: {
3: private double _salary = 0;
4: private string _employeeName = "";
5: public event PropertyChangedEventHandler PropertyChanged;
6:
7: public string EmployeeName
8: {
9: get { return _employeeName; }
10: set
11: {
12: _employeeName = value;
13: OnPropertyChanged("EmployeeName");
14: }
15: }
16:
17: public void Calculate() { OnPropertyChanged("Salary"); }
18:
19: public double Salary
20: {
21: get
22: {
23: _salary = 0;
24: if (!string.IsNullOrEmpty(_employeeName))
25: {
26: //Supponiamo un'operazione che impieghi un certo tempo...
27: System.Threading.Thread.Sleep(3000);
28:
29: switch (_employeeName.ToLower())
30: {
31: case "pietro":
32: _salary = 1000;
33: break;
34: case "giovanni":
35: _salary = 2000;
36: break;
37: default:
38: _salary = 0;
39: break;
40: }
41: }
42: return _salary;
43: }
44: }
45:
46: protected void OnPropertyChanged(string prop)
47: {
48: if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(prop));
49: }
50:
51: public string WaitMessage1 { get { return "Loading..."; } }
52:
53: public string WaitMessage2
54: {
55: get
56: {
57: System.Threading.Thread.Sleep(2000);
58: return "Loading...please wait";
59: }
60: }
Il cui funzionamento è abbastanza semplice: secondo del nome dell’impiegato selezionato tramite la proprietà EmployeeName quando viene richiamato Calculate() viene eseguita una notifica di cambiamento tramite OnPropertyChanged(“…”) della proprietà Salary (Ci servirà nel codice XAML). Particolare attenzione deve essere posta alle proprietà WaitMessage1 e WaitMessage2, utilizzate nella UI per visualizzare due messaggi di attesa per l’utente: il primo subito, il secondo da visualizzare nel caso in cui l’operazione “di calcolo” si prolunghi oltre un certo tempo.
Per testare il funzionamento della classe utilizziamo una Windows WPF molto semplice:
Il codice XAML associato alla controllo label in cui viene visualizzato il salario dell’impiegato (calcolato), e a cui è associato il PriorityBinding è il seguente:
1: <Label.Content>
2: <PriorityBinding>
3: <Binding Path="Salary" Source="{StaticResource es}" IsAsync="True" />
4: <Binding Path="WaitMessage2" IsAsync="True" Source="{StaticResource es}"/>
5: <Binding Path="WaitMessage1" IsAsync="False" Source="{StaticResource es}"/>
6: </PriorityBinding>
7: </Label.Content>
Associamo i Binding nell’ordine in cui vogliamo vengano eseguiti: Salary, ritorna il valore dello stipendio secondo dell’impiegato specificato nel campo TextBox, WaitMessage2 è il messaggio che dovrebbe essere visualizzato se l’operazione di calcolo necessità più di due secondi, WaitMessage1 è il primo messaggio da visualizzare non appena viene fatto click sul bottone Calcola Stipendio. Affinché tutto funzioni è necessario che la proprietà IsAsync del Binding sulle proprietà Salary e WaitMessage2 sia impostato su True altrimenti l’operazione attenderà il completamento dell’associazione prima di eseguire il prossimo (eventuale) Binding (perdendo i vantaggi del PriorityBinding).
La risorsa statica es, è dichiarata a livello di Windows in questo modo:
<Window.Resources>
<local:Data x:Key="es"/>
</Window.Resources>