注意WPF中綁定使用的是引用類型

綁定(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 }
View Code

實際運行起來後,我選中了一行之後,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進行一次深拷貝(注意:必定是深拷貝,不然又只是一次簡單的引用關係),數據的鏈接關係都經過深拷貝來實現,它們的關係以下圖:

 

具體實現晚些時候有時間再放上... ...

相關文章
相關標籤/搜索