天天看點

資料綁定需要注意的一些

本文摘要:

1:實體類的綁定;

2:實體類集合的綁定;

3:自定義的實體類集合,如ObservableDictionary;

4:Path的文法;

1:實體類的綁定

         了解WPF資料綁定,首先需要了解接口INotifyCollectionChanged。

         場景1:UI顯示學生資訊,當學生姓名發生改變的時候,就需要實時地表現到UI上。在這種情況下,就需要Student這個類實作INotifyCollectionChanged接口。如下:

public class Student : INotifyPropertyChanged
    {
        string firstName;
        public string FirstName { get { return firstName; } set { firstName = value; Notify("FirstName"); } }
        string lastName;
        public string LastName { get { return lastName; } set { lastName = value; Notify("LastName"); } }

        public Student(string firstName, string lastName)
        {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        void Notify(string propName)
        {
            if (PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propName));
            }
        }

        #region INotifyPropertyChanged Members
        public event PropertyChangedEventHandler PropertyChanged;
        #endregion
    }      

         可以看到,實體類Student需要實作的INotifyPropertyChanged 接口成員為:public event PropertyChangedEventHandler PropertyChanged。當我們在WPF的UI控件中實作綁定的時候,UI會自動為PropertyChanged指派(為UI的控件對象的OnPropertyChanged)。其次,需要在屬性SET方法中實作調用委托變量PropertyChanged,即如上代碼片段中的Notify。

         設計一個前台界面:

<Window x:Class="WpfApplication1.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window1" Height="345" Width="490">
    <DockPanel x:Name="dockPanel">
        <TextBlock DockPanel.Dock="Top">
            <TextBlock>firstName:</TextBlock>
            <TextBox Text="{Binding Path=FirstName}" Width="100"></TextBox>
            <TextBlock>lastName:</TextBlock>
            <TextBox Text="{Binding Path=LastName}" Width="100"></TextBox>
        </TextBlock>
        <Button x:Name="btnView" DockPanel.Dock="Bottom" Height="30">view</Button>
    </DockPanel>
</Window>      

         此界面對應背景檔案:

public partial class Window1 : Window
    {
        public Window1()
        {
            InitializeComponent();
            Student student = new Student("firstname1", "lastName1");
            dockPanel.DataContext = student;
            btnView.Click += new RoutedEventHandler(delegate(object sender, RoutedEventArgs e)
                {
                    MessageBox.Show(student.FirstName);
                });
        }
    }      

      以上全部代碼實作了場景1,同時,我們還會發現,如果在UI中修改了student的FirstName或者LastName。則背景代碼中的student對象的屬性會自動同步變化。

2:實體類集合的綁定

         既然對于單個實體類的資料綁定已經實作,那麼有沒有辦法對清單資料,也就是實體類集合進行資料的綁定呢?.NET提供了INotifyCollectionChanged,任何實作了該接口的集合類,都可以用來滿足如下場景。

         場景2:UI顯示學生清單資訊。在背景增加或删除學生,或修改清單中單個學生的資訊,在前台都能同步顯示。同時,前台修改資料,也能同步反應到綁定源中。

         在場景2的代碼中,使用了ObservableCollection集合類,這個類就是實作了INotifyCollectionChanged接口的一個集合類。

         前台代碼:

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <DockPanel x:Name="dockPanel">
        <TextBlock DockPanel.Dock="Top">
            <TextBlock VerticalAlignment="Center">FirstName:</TextBlock>
            <TextBox x:Name="tbFirstName" Text="{Binding Path=FirstName}" Width="150"></TextBox>
            <TextBlock VerticalAlignment="Center">LastName:</TextBlock>
            <TextBox x:Name="tbLastName" Text="{Binding Path=LastName}" Width="150"></TextBox>
        </TextBlock>
        <Button DockPanel.Dock="Bottom" x:Name="addButton">Add</Button>
        <ListBox ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True">
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock>
                        <TextBlock Text="{Binding Path=FirstName}" Width="150"></TextBlock>
                        <TextBlock Text="{Binding Path=LastName}" Width="150"></TextBlock>
                    </TextBlock>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </DockPanel>
</Window>      

         對應的背景代碼:

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            ObservableCollection<Student> students = new ObservableCollection<Student>();
            students.Add(new Student("firstName1", "lastName1"));
            students.Add(new Student("firstName2", "lastName2"));
            this.addButton.Click += (object sender, RoutedEventArgs e) =>
                {
                    students.Add(new Student(tbFirstName.Text.Trim(), tbLastName.Text.Trim()));
                };
            dockPanel.DataContext = students;
        }
    }      

         以上代碼片段,實作了場景2的所有功能。可以看到,在背景代碼中,并沒有為ListBox指定任何資料源,為何ListBox仍舊可以自動綁定資料?在WPF中,如果一個控件為綁定資料源,則會自動到父控件中去找,比如,本示例中,ListBox便會自動綁定dockPanel的資料源。而兩個TextBox,則是綁定集合類中的實體類的相關屬性。其預設綁定的是索引為0的元素。

         ListBox的屬性IsSynchronizedWithCurrentItem="True"表示,如果集合類中的實體屬性在背景發生變化,則ListBox将會在UI中動态顯示變化。      

3:自定義的實體類集合,如ObservableDictionary

         在上文中提到了提供了,任何實作了INotifyCollectionChanged接口的集合類,都可以用來實作場景2。結果我們用到.NET提供的ObservableCollection集合類。在實際的應用中,會常常用到字典集合類,而.NET卻沒有提供。這就需要我們自己來實作一個ObservableDictionary。以下是該類的下載下傳位址:

         代碼下載下傳位址:http://download.csdn.net/source/2110250。

4:Path的文法

     使用 Path 屬性可以指定您要綁定到的源值:

  • 在最簡單的情況下,Path 屬性值是要用于綁定的源對象的屬性名,如 Path=PropertyName。
  • 通過類似于 C# 中使用的文法,可以指定屬性的子屬性。例如,子句 Path=ShoppingCart.Order 設定與對象或屬性 ShoppingCart 的 Order 子屬性的綁定。
  • 若要綁定到附加屬性,應在附加屬性周圍放置圓括号。例如,若要綁定到附加屬性 DockPanel..::.Dock,則文法是 Path=(DockPanel.Dock)。
  • 可以在要應用索引器的屬性名後面的方括号内指定屬性的索引器。例如,子句 Path=ShoppingCart[0] 将綁定設定為與屬性的内部索引處理文本字元串“0”的方式對應的索引。此外,還支援多個索引器。
  • 可以在 Path 子句中混合索引器和子屬性;例如,Path=ShoppingCart.ShippingInfo[MailingAddress,Street].
  • 在索引器内部,您可以有多個由逗号 (,) 分隔的索引器參數。可以使用圓括号指定每個參數的類型。例如,您可以有 Path="[(sys:Int32)42,(sys:Int32)24]",其中 sys 映射到 System 命名空間。
  • 如果源為集合視圖,則可以用斜杠 (/) 指定目前項。例如,子句 Path=/ 用于設定到視圖中目前項的綁定。如果源為集合,則此文法指定預設集合視圖的目前項。
  • 可以結合使用屬性名和斜杠來周遊作為集合的屬性。例如,Path=/Offices/ManagerName 指定源集合的目前項,該源集合包含也作為集合的 Offices 屬性。其目前項是一個包含 ManagerName屬性的對象。
  • 也可以使用句點 (.) 路徑綁定到目前源。例如,Text=”{Binding}” 等效于 Text=”{Binding Path=.}”。