綁定(Binding)是WPF提供的一個很是方便的特性,它能夠方便的實現一個WPF的MVVM結構。ide
既能夠實現數據驅動UI變化,也能夠作到End-user在UI上的修改實現的反映到數據上。ui
可是有一點必須注意的是:WPF的數據基本上都是使用的引用類型,引用類型的特性就是在傳遞過程當中,數據本體是沒有變化的。this
可能你對數據進行了幾回不經意的傳遞後,對變量作的修改居然體如今了UI的變化。這時,Debug又變成了一件很痛苦的事情(尤爲是當項目比較龐大的時候)。spa
首先來看一個比較常見的例子。code
我有一個如上圖的UI,左邊一個ListView,右邊有一個TextBox用於編輯,代碼以下:blog
1 using System.Collections.Generic; 2 using System.Collections.ObjectModel; 3 using System.ComponentModel; 4 using System.Runtime.CompilerServices; 5 using System.Windows; 6 7 namespace WpfApplication2 8 { 9 /// <summary> 10 /// Interaction logic for MainWindow.xaml 11 /// </summary> 12 public partial class MainWindow : Window 13 { 14 private MainViewModel FViewModel = null; 15 public MainViewModel ViewModel 16 { 17 get { return FViewModel; } 18 set 19 { 20 if (value != FViewModel) 21 FViewModel = value; 22 } 23 } 24 public MainWindow() 25 { 26 InitializeComponent(); 27 28 FViewModel = new MainViewModel(); 29 30 this.DataContext = ViewModel; 31 } 32 } 33 34 public class MainViewModel : INotifyPropertyChanged 35 { 36 public MainViewModel() 37 { 38 DataModels = new ObservableCollection<MainDataModel>(BuildHardCodeList()); 39 } 40 41 public event PropertyChangedEventHandler PropertyChanged; 42 private void RaisePropertyChanged([CallerMemberName] string aMembName = "") 43 { 44 if (PropertyChanged != null) 45 { 46 PropertyChanged(this, new PropertyChangedEventArgs(aMembName)); 47 } 48 } 49 50 private static IEnumerable<MainDataModel> BuildHardCodeList() 51 { 52 yield return new MainDataModel() { Name = "DataModel - 1" }; 53 yield return new MainDataModel() { Name = "DataModel - 2" }; 54 yield return new MainDataModel() { Name = "DataModel - 3" }; 55 yield return new MainDataModel() { Name = "DataModel - 4" }; 56 yield return new MainDataModel() { Name = "DataModel - 5" }; 57 } 58 59 public ObservableCollection<MainDataModel> DataModels { get; set; } 60 61 private MainDataModel FCurrentDataModel; 62 public MainDataModel CurrentDataModel 63 { 64 get { return FCurrentDataModel; } 65 set 66 { 67 if (value != FCurrentDataModel) 68 { 69 FCurrentDataModel = value; 70 RaisePropertyChanged(); 71 } 72 } 73 } 74 } 75 public class MainDataModel 76 { 77 public string Name { get; set; } 78 79 public override string ToString() 80 { 81 return Name; 82 } 83 } 84 }
實際運行起來後,我選中了一行之後,Name-TextBox用選中的item的Name進行了填充。get
我修改了Name的內容,鼠標移到下一個TextBox。string
這時發現ListView的相應記錄也修改了。這就是引用類型產生的做用。it
其時在大部分狀況下,咱們是不但願ListView的內容進行改變,直到我點擊Save button。io
要想實現這個需求就必須把CurrentDataModel與DataModels的鏈接打斷掉。
如今DataModel - 1的數據存儲方式如上圖,堆棧中只有一份DataModel - 1, ListView與TextBox全都引用這一份數據,當TextBox進行修改時,這惟一的一份數據進行了修改,固然就會更新ListView。
要打斷這種引用關係,就須要對DataModel - 1進行一次深拷貝(注意:必定是深拷貝,不然又只是一次簡單的引用關係),數據的鏈接關係都經過深拷貝來實現,它們的關係以下圖:
具體實現晚些時候有時間再放上... ...