[C# | XAML] 如何對ListBox做資料繫結(DataBinding)

  • 9587
  • 0
  • C#
  • 2014-05-11

此篇介紹如何繫結到資料集合的元件,如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)); }
       }

 

範例檔案請點此

 

參考資料:

資料繫結概觀

Update Listbox.ItemsSource when not using ObservableCollection

 


 

文章中的敘述如有觀念不正確錯誤的部分,歡迎告知指正 謝謝 =)

另外要轉載請附上出處 感謝