2017年12月6日 星期三

資料繫結(DataBinding) - 用List 與 ObservableCollection 作為繫結的資料來源的差異

Ref:
https://dotblogs.com.tw/v6610688/2014/04/07/xaml_csharp_listbox_databinding_by_observablecollection



此篇介紹如何繫結到資料集合的元件,如ListBox、ListView等等的元件。
這些元件都是集合,皆有繼承ItemsControl,所以在繫結實的方式會比較不一樣。

在這邊以ListBox元件作為範例。
並且分別介紹與用List 與 ObservableCollection 作為繫結的資料來源的差異

介紹




在此篇介紹如何繫結到資料集合的元件,如ListBox、ListView等等的元件。
這些元件都是集合,皆有繼承ItemsControl,所以在繫結實的方式會比較不一樣。

在這邊以ListBox元件作為範例。
並且分別介紹與用List<T> 與 ObservableCollection<T> 作為繫結的資料來源的差異

範例介紹:




本範例如用Windows Store App
為了要繫結至ListBox顯示資料的元件,在邏輯端通常會與用List<T>作為保存資料的結構方式,這邊以WantedData類別為例:
用來記錄想要的東西與價錢
public class WantedData {
        public string Content{ get; set; }
        public int Price { get; set; }
    }
首先是XAML中的程式碼,在這邊用了一個ListBox顯示列出來的願望清單
並另外給予新增的部分,分別可以輸入想要的物品名稱與價錢,如下
<ListBox Name="wantedListBox1" FontSize="32" HorizontalAlignment="Left" Height="599" Margin="30,144,0,0" VerticalAlignment="Top" Width="382">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Content}" FontSize="24"/>
                        <TextBlock Text="{Binding Price}" FontSize="24"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

        <ListBox x:Name="wantedListBox2"  FontSize="32" HorizontalAlignment="Left" Height="599" Margin="481,144,0,0" VerticalAlignment="Top" Width="388">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <StackPanel Orientation="Horizontal">
                        <TextBlock Text="{Binding Content}" FontSize="24"/>
                        <TextBlock Text="{Binding Price}" FontSize="24"/>
                    </StackPanel>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>

        <Button Content="加入清單" FontSize="32" HorizontalAlignment="Left" Margin="921,422,0,0" VerticalAlignment="Top" Height="66" Width="154" Click="Button_Click"/>
        <TextBox Name="wantedText" HorizontalAlignment="Left" Margin="921,211,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Height="48" Width="154"/>
        <TextBlock  HorizontalAlignment="Left" Margin="921,144,0,0" TextWrapping="Wrap" Text="想要的東西:" FontSize="40" VerticalAlignment="Top"/>
        <TextBox x:Name="wantedPriceText" HorizontalAlignment="Left" Margin="921,353,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Height="48" Width="154"/>
        <TextBlock  HorizontalAlignment="Left" Margin="921,281,0,0" TextWrapping="Wrap" Text="價錢:" FontSize="40" VerticalAlignment="Top"/>

重新定義了ListBox的資料樣板DataTemplate,並繫結到WantedData 的資料
介面如下圖:
4-7-listbox-databinding

以下便來介紹如何實作。

透過ObservableCollection<T> 作為繫結的資料來源




一般而言會建議使用ObservableCollection<T> 作為繫結的資料來源,因為ObservableCollection<T>實作了INotifyCollectionChanged介面,相當於前一篇的INotifyPropertyChanged介面,告知UI端繫結的集合資料更改。

1.在MainPage中建立資料

ObservableCollection<WantedData> wantedDataCollection = new ObservableCollection<WantedData>
       {
            new WantedData{Content = "筆記本" , Price = 30},
           new WantedData{Content = "鞋子" , Price = 2000}
       };
這邊是範例資料,如果沒有的話就是new就好。

2.並在建構子設定ItemsSource的繫結來源為wantedDataList

//繫結來源
wantedListBox2.ItemsSource = wantedDataCollection;

3.在按鈕Click時新增資料到wantedDataCollection

//ObservableCollection
wantedDataCollection.Add(new WantedData { Content = wantedText.Text, Price = Convert.ToInt16(wantedPriceText.Text) });

以上完成!因為ObservableCollection幫我們實現了介面,所以我們不用像一般的簡單資料繫結,要去實現介面,只要向上面這樣,三個步驟加上自己要淳放資料的類別建立好即可。

List<T>作為繫結的資料來源




透過List<T>會因為沒有實現INotifyCollectionChanged介面所以要多兩個小步驟

1.初始化

List<WantedData> wantedDataList = new List<WantedData>
       {
           new WantedData{Content = "筆記本" , Price = 30},
           new WantedData{Content = "鞋子" , Price = 2000}
       };

2.建構時繫結來源

//繫結來源
wantedListBox1.ItemsSource = wantedDataList;

3.新增資料時,重新指定ItemsSource來源!

wantedDataList.Add(new WantedData { Content = wantedText.Text ,Price = Convert.ToInt16(wantedPriceText.Text) });

//使用List需要在指定一次
wantedListBox1.ItemsSource = null;
wantedListBox1.ItemsSource = wantedDataList;
因為沒有告知UI更新的關係,所以我們要主動重新在指定一次。

最後的畫面如下;
4-7-listbox-databinding-result

結合更新資料繫結




但是只有這樣,當我們要新增更改資料的話,會無法更改,原因在於,我們的WantedData沒有實作INotifyPropertyChanged的關係,所以當資料被更改時,UI的部分不會被更改
INotifyPropertiesChanged

於是改成如下:
//INotifyPropertyChanged 用來協助更新資料
   public class WantedData : INotifyPropertyChanged
   {
       string content;
       int price;
       public string Content
       {
           get { return content; }
           set
           {
               content = value;
               NotifyPropertyChanged("Content");
           }
       }
       public int Price
       {
           get { return price; }
           set
           {
               price = value;
               NotifyPropertyChanged("Price");
           }
       }

       public event PropertyChangedEventHandler PropertyChanged;
       protected void NotifyPropertyChanged(string propertyName)
       {
           if (PropertyChanged != null)
           { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); }
       }


參考資料:



沒有留言:

張貼留言