前段時間,抽空用WPF做了個郵件群發工具;接下來想用兩三篇博客將開發過程中遇到的困惑和積累的經驗跟大家分享下,也算是拋磚引玉了,盡管對WinForm開發很熟悉,但畢竟它們之間差別比較大——從界面的呈現到內部的控制等。本篇博客看標題就可清楚,我要說的是進度條(屬性改變通知機制)的實現!
進度條在WinForm中實現很容易,代碼如下:
1 private void button1_Click(object sender, EventArgs e) 2 { 3 int num = 100; 4 this.progressBar1.Maximum = num; 5 for (int i = 0; i <= num; i = i + 10) 6 { 7 this.progressBar1.Value = i; 8 Thread.Sleep(1000); 9 } 10 }
看似正常的邏輯,在WPF中卻沒有效果,其原因經測試和分析得出:應該是WinForm里控件和界面在同一個線程中,而WPF里它們不在同一個線程中。
現在切入正題,談談WPF中進度條(屬性改變通知機制)的實現——
發送結果信息實體類
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.ComponentModel; 6 7 namespace EmailBatchSend 8 { 9 /// <summary> 10 /// 發送結果信息實體 11 /// </summary> 12 internal class SendResult : INotifyPropertyChanged 13 { 14 public event PropertyChangedEventHandler PropertyChanged; 15 16 private string _progressBarNumShow = string.Empty; 17 /// <summary> 18 /// 進度條數字顯示 19 /// </summary> 20 public string ProgressBarNumShow 21 { 22 get 23 { 24 return this._progressBarNumShow; 25 } 26 set 27 { 28 this._progressBarNumShow = value; 29 OnPropertyChanged("ProgressBarNumShow"); 30 } 31 } 32 33 private string _sendResultMes = string.Empty; 34 /// <summary> 35 /// 發送結果消息 36 /// </summary> 37 public string SendResultMes 38 { 39 get 40 { 41 return this._sendResultMes; 42 } 43 set 44 { 45 this._sendResultMes = value; 46 OnPropertyChanged("SendResultMes"); 47 } 48 } 49 50 private string _sendFailEmails = string.Empty; 51 /// <summary> 52 /// 發送失敗的結果消息 53 /// </summary> 54 public string SendFailEmails 55 { 56 get 57 { 58 return this._sendFailEmails; 59 } 60 set 61 { 62 this._sendFailEmails = value; 63 OnPropertyChanged("SendFailEmails"); 64 } 65 } 66 67 private int _currentSendNum; 68 /// <summary> 69 /// 當前正在發送的 第幾個 70 /// </summary> 71 public int CurrentSendNum 72 { 73 get 74 { 75 return this._currentSendNum; 76 } 77 set 78 { 79 this._currentSendNum = value; 80 OnPropertyChanged("CurrentSendNum"); 81 } 82 } 83 84 private bool _sendControlIsEnabled = true; 85 /// <summary> 86 /// 發送郵件 控件是否可用 87 /// </summary> 88 public bool SendControlIsEnabled { 89 get 90 { 91 return this._sendControlIsEnabled; 92 } 93 set 94 { 95 this._sendControlIsEnabled = value; 96 OnPropertyChanged("SendControlIsEnabled"); 97 } 98 } 99 100 private void OnPropertyChanged(string propertyName) 101 { 102 if (this.PropertyChanged != null) 103 this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 104 } 105 } 106 }
界面上的使用
圖001
通過上面的代碼,可以看出SendResult類實現了INotifyPropertyChanged——此接口的用途是向客戶端發出某一屬性值已更改的通知,這個接口的定義很簡單,如下:
1 namespace System.ComponentModel 2 { 3 // 摘要: 4 // 向客戶端發出某一屬性值已更改的通知。 5 public interface INotifyPropertyChanged 6 { 7 // 摘要: 8 // 在更改屬性值時發生。 9 event PropertyChangedEventHandler PropertyChanged; 10 } 11 }
此接口中只有一個PropertyChanged事件的定義,顧名思義:此事件會在屬性值發生改變時被觸發調用,且不需要實現,我比較好奇其內部的具體實現。重點看圖001中的紅色和紫色區域,通過{Binding 屬性名}的方式分別設置了進度條的當前值和發送按鈕的可用狀態,而{Binding 屬性名}的用法在WPF中很普遍,其使用有點兒類似於WebForm中的數據綁定控件中的<%#Eval("屬性名")>,既然是類似,那同樣的還需要給控件設置一個類似DataSource的東東——使控件的數據綁定和具體的數據對象關聯起來,才能實現相應的功能。
1 SendResult sendResult = new SendResult(); 2 this.progressBar.DataContext = sendResult;
上面的代碼就相當於是設置progressBar的數據源,只不過在WPF中它有另外一個名稱叫:DataContext 數據上下文,幾乎所有的WPF控件都有DataContext此屬性,即都支持數據綁定。
到這里,進度條的實現已OK,效果圖如下:
因為對WPF根本談不上精通,如果有錯解的地方,希望大家能指出或談下自己的看法,感興趣的朋友,可以留言相互交流學習!