程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WPF學習筆記 - 9. Binding (2)

WPF學習筆記 - 9. Binding (2)

編輯:關於.NET

4. 綁定到集合

在實際開發中,我們通常是將一個集合數據對象 (比如數據表) 綁定到一個 DataGrid 或者 ListBox 列表控件上,這時候我們就需要使用到集合綁定方式。WPF 特意為我們實現了一個 System.Collections.ObjectModel.ObservableCollection<T> 泛型集合,省卻了我們寫具備變更通知功能集合代碼的時間。

Window1.xaml

<Window x:Class="Learn.WPF.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  Title="Window1">
  <Grid>
    <StackPanel>
      <ListBox x:Name="listbox1"></ListBox>
    </StackPanel>
  </Grid>
</Window>

Window1.xaml.cs

public class Personal
{
  public string Name { get; set; }
  public int Age { get; set; }
  public string Sex { get; set; }
}
public class PersonalList : ObservableCollection<Personal>
{
}
public partial class Window1 : Window
{
  public Window1()
  {
    InitializeComponent();
    var list = new PersonalList
    {
      new Personal { Name = "Tom", Age = 10, Sex = "Male" },
      new Personal { Name = "Mary", Age = 15, Sex = "Female" },
      new Personal { Name = "Jack", Age = 12, Sex = "Male" },
    };
    var binding = new Binding{ Source = list };
    this.listbox1.SetBinding(ListBox.ItemsSourceProperty, binding);
    this.listbox1.DisplayMemberPath = "Name";
  }
}

注意使用 DisplayMemberPath 屬性指定 ListBoxItem 的內容,否則會調用 ToString() 來顯示結果。

當然,我們也可以直接綁定邏輯資源中的列表數據。

Window1.xaml

<Window x:Class="Learn.WPF.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:my="clr-namespace:Learn.WPF"
  Title="Window1">
  <Window.Resources>
    <my:PersonalList x:Key="personals" >
      <my:Personal Name="Tom" Age="10" Sex="Male" />
      <my:Personal Name="Mary" Age="15" Sex="Female" />
      <my:Personal Name="Jack" Age="12" Sex="Male" />
    </my:PersonalList>
  </Window.Resources>
  <Grid>
    <StackPanel>
      <ListBox x:Name="listbox2"
        ItemsSource="{Binding Source={StaticResource personals}}"
        DisplayMemberPath="Name">
      </ListBox>
    </StackPanel>
  </Grid>
</Window>

為了使用 Personal 和 PersonalList,我們引入了一個 CLR Namespace。

在主從結構 (Master-Detail) 顯示中,我們通常要實現 "選擇項跟蹤" 功能,也就是說當我們選中主表的某個記錄時,其他細節控件要同步刷新該記錄的細節內容。

<Window x:Class="Learn.WPF.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:my="clr-namespace:Learn.WPF"
  Title="Window1">
  <Window.Resources>
    <my:PersonalList x:Key="personals" >
      <my:Personal Name="Tom" Age="10" Sex="Male" />
      <my:Personal Name="Mary" Age="15" Sex="Female" />
      <my:Personal Name="Jack" Age="12" Sex="Male" />
    </my:PersonalList>
  </Window.Resources>
  <Grid>
    <StackPanel>
      <ListBox x:Name="listbox1"
        ItemsSource="{Binding Source={StaticResource personals}}"
        DisplayMemberPath="Name"
        IsSynchronizedWithCurrentItem="True">
      </ListBox>

      <Label x:Name="lblName" Content="{Binding Source={StaticResource personals}, Path=Name}" />
      <Label x:Name="lblAge" Content="{Binding Source={StaticResource personals}, Path=Age}"/>
      <Label x:Name="lblSex" Content="{Binding Source={StaticResource personals}, Path=Sex}"/>
    </StackPanel>
  </Grid>
</Window>

我們將 ListBox.IsSynchronizedWithCurrentItem 置為 True,這樣當我們改變 ListBox 選擇項時,下面三個標簽會自動同步變更為被選中記錄的信息。

當然,我們還可以使用多個 ListBox,就像真正的主從表顯示那樣相互影響。

<Window x:Class="Learn.WPF.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:my="clr-namespace:Learn.WPF"
  Title="Window1">
  <Window.Resources>
    <my:PersonalList x:Key="personals" >
      <my:Personal Name="Tom" Age="10" Sex="Male" />
      <my:Personal Name="Mary" Age="15" Sex="Female" />
      <my:Personal Name="Jack" Age="12" Sex="Male" />
    </my:PersonalList>
  </Window.Resources>
  <Grid>
    <StackPanel>
      <ListBox x:Name="listbox1"
        ItemsSource="{Binding Source={StaticResource personals}}"
        DisplayMemberPath="Name"
        IsSynchronizedWithCurrentItem="True">
      </ListBox>

      <ListBox x:Name="listbox2"
        ItemsSource="{Binding Source={StaticResource personals}}"
        DisplayMemberPath="Age"
        IsSynchronizedWithCurrentItem="True">
      </ListBox>
    </StackPanel>
  </Grid>
</Window>

有一點需要說明,IsSynchronizedWithCurrentItem 不支持多項選擇同步。

5. DataContext 共享源

在上面的例子中,我們需要將同一資源綁定到多個 UI 元素上,很顯然到處寫 "{Binding Source={StaticResource personals}}" 是件很繁瑣且不利於修改的做法。WPF 提供了一個稱之為 "數據上下文 (DataContext)" 的東西讓我們可以在多個元素上共享一個源對象,只需將其放到父元素 DataContext 屬性即可。

<Window x:Class="Learn.WPF.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:my="clr-namespace:Learn.WPF"
  Title="Window1">
  <Window.Resources>
    <my:PersonalList x:Key="personals" >
      <my:Personal Name="Tom" Age="10" Sex="Male" />
      <my:Personal Name="Mary" Age="15" Sex="Female" />
      <my:Personal Name="Jack" Age="12" Sex="Male" />
    </my:PersonalList>
  </Window.Resources>
  <Grid>
    <StackPanel DataContext="{StaticResource personals}">
      <ListBox x:Name="listbox1"
        ItemsSource="{Binding}"
        DisplayMemberPath="Name"
        IsSynchronizedWithCurrentItem="True">
      </ListBox>

      <Label x:Name="lblName" Content="{Binding Path=Name}" />
      <Label x:Name="lblAge" Content="{Binding Path=Age}"/>
      <Label x:Name="lblSex" Content="{Binding Path=Sex}"/>
    </StackPanel>
  </Grid>
</Window>

當我們不給 Binding 擴展標志指定 Source 屬性時,它會自動尋找上級父元素的數據上下文。

當然,我們也可以在代碼中做同樣的事情。

Window1.xaml

<Window x:Class="Learn.WPF.Window1"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:my="clr-namespace:Learn.WPF"
  Title="Window1">
  <Grid>
    <StackPanel x:Name="stackPanel1">
      <ListBox x:Name="listbox1"
        ItemsSource="{Binding}"
        DisplayMemberPath="Name"
        IsSynchronizedWithCurrentItem="True">
      </ListBox>

      <Label x:Name="lblName" Content="{Binding Path=Name}" />
      <Label x:Name="lblAge" Content="{Binding Path=Age}"/>
      <Label x:Name="lblSex" Content="{Binding Path=Sex}"/>
    </StackPanel>
  </Grid>
</Window>

Window1.xaml.cs

public partial class Window1 : Window
{
  public Window1()
  {
    InitializeComponent();
    var list = new PersonalList {
     new Personal{Name="Tom", Age=10, Sex="Male"},
     new Personal{Name="Mary", Age=15, Sex="Female"},
     new Personal{Name="Jack", Age=12, Sex="Male"},
    };
    this.stackPanel1.DataContext = list;
  }
}

從上面的例子中,我們可以看出使用 DataContext 使得數據和 UI 分離更加靈活,因為 DataContext 可以跨越多級父元素。比如我們可以直接將數據源設置為 Window.DataContext。

public partial class Window1 : Window
{
  public Window1()
  {
    ... ...
    this.DataContext = list;
  }
}

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved