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

WPF學習筆記 - 11. Binding (4)

編輯:關於.NET

8. 集合視圖當綁定到一個集合對象時,WPF 總是默認提供一個視圖 (CollectionViewSource)。視圖會關聯到源集合上,並自動將相關的操作在目標對象上顯示出來。

(1) 排序

向 CollectionViewSource.SortDescriptions 屬性中插入一個或多個排序條件 (SortDescription) 即可實現單個或多個條件排序。

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="15" Sex="Male" />
      <my:Personal Name="Mary" Age="11" 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}">
        <ListBox.ItemTemplate>
          <DataTemplate>
            <StackPanel Orientation="Horizontal">
              <TextBlock Text="{Binding Path=Name}" />
              <TextBlock>,</TextBlock>
              <TextBlock Text="{Binding Path=Age}" />
              <TextBlock>,</TextBlock>
              <TextBlock Text="{Binding Path=Sex}" />
            </StackPanel>
          </DataTemplate>
        </ListBox.ItemTemplate>
      </ListBox>
    </StackPanel>
  </Grid>
</Window>

Window1.xaml.cs

public partial class Window1 : Window
{
  public Window1()
  {
    InitializeComponent();
    var personals = this.FindResource("personals");
    var view = CollectionViewSource.GetDefaultView(personals);
    view.SortDescriptions.Add(new SortDescription("Age", ListSortDirection.Ascending));
  }
}

對 CollectionViewSource.SortDescriptions 的修改會直接反應在界面顯示上。

protected void ButtonClick(object sender, RoutedEventArgs e)
{
  var personals = this.FindResource("personals");
  var view = CollectionViewSource.GetDefaultView(personals);
  var direction = sender == btnDesc ? ListSortDirection.Descending : ListSortDirection.Ascending;
  view.SortDescriptions.Clear();
  view.SortDescriptions.Add(new SortDescription("Age", direction));
}

當然,我們可以直接在 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"
  xmlns:model="clr-namespace:System.ComponentModel;assembly=WindowsBase"
  Title="Window1">
  <Window.Resources>
    <my:PersonalList x:Key="personals" >
      <my:Personal Name="Tom" Age="15" Sex="Male" />
      <my:Personal Name="Mary" Age="11" Sex="Female" />
      <my:Personal Name="Jack" Age="12" Sex="Male" />
    </my:PersonalList>
    <CollectionViewSource x:Key="cvs" Source="{StaticResource personals}">
      <CollectionViewSource.SortDescriptions>
        <model:SortDescription PropertyName="Age" />
        <model:SortDescription PropertyName="Sex" Direction="Descending" />
      </CollectionViewSource.SortDescriptions>
    </CollectionViewSource>
  </Window.Resources>
  <Grid>
    <StackPanel DataContext="{StaticResource cvs}">
      <ListBox x:Name="listbox1" ItemsSource="{Binding}">
        <ListBox.ItemTemplate>
          <DataTemplate>
            <StackPanel Orientation="Horizontal">
              <TextBlock Text="{Binding Path=Name}" />
              <TextBlock>,</TextBlock>
              <TextBlock Text="{Binding Path=Age}" />
              <TextBlock>,</TextBlock>
              <TextBlock Text="{Binding Path=Sex}" />
            </StackPanel>
          </DataTemplate>
        </ListBox.ItemTemplate>
      </ListBox>
    </StackPanel>
  </Grid>
</Window>

需要注意的地方包括:

引入了 xmlns:model="clr-namespace:System.ComponentModel;assembly=WindowsBase" 命名空間。

使用 CollectionViewSource 在資源中定義視圖排序條件,注意使用 Source 屬性綁定到 personals 資源。

目標對象數據源(DataContext)綁定到視圖(cvs)而不是數據源(personals)。

(2) 分組

CollectionViewSource.GroupDescriptions 屬性用來控制對數據源進行分組。

Window1.xaml.cs

public partial class Window1 : Window
{
  public Window1()
  {
    InitializeComponent();
    var personals = this.FindResource("personals");
    var view = CollectionViewSource.GetDefaultView(personals);
    
    view.GroupDescriptions.Add(new PropertyGroupDescription("Sex"));
  }
}

按性別進行分組,只是輸出結果沒啥直觀效果。

要看到效果,我們還必須為 ListBox 添加一個 GroupStyle,基於一貫偷懶的理由,我們可以直接使用系統內置的 GroupStyle.Default。

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="15" Sex="Male" />
      <my:Personal Name="Mary" Age="11" 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}">
        <ListBox.GroupStyle>
          <x:Static Member="GroupStyle.Default"/>
        </ListBox.GroupStyle>
      
        <ListBox.ItemTemplate>
          <DataTemplate>
            <StackPanel Orientation="Horizontal">
              <TextBlock Text="{Binding Path=Name}" />
              <TextBlock>,</TextBlock>
              <TextBlock Text="{Binding Path=Age}" />
              <TextBlock>,</TextBlock>
              <TextBlock Text="{Binding Path=Sex}" />
            </StackPanel>
          </DataTemplate>
        </ListBox.ItemTemplate>
      </ListBox>
    </StackPanel>
  </Grid>
</Window>

這回看上去好多了。

當然,GroupDescriptions 同樣也可以寫在 XAML 裡。

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"
  xmlns:data="clr-namespace:System.Windows.Data;assembly=PresentationFramework"
  Title="Window1">
  <Window.Resources>
    <my:PersonalList x:Key="personals" >
      <my:Personal Name="Tom" Age="15" Sex="Male" />
      <my:Personal Name="Mary" Age="11" Sex="Female" />
      <my:Personal Name="Jack" Age="12" Sex="Male" />
    </my:PersonalList>
    <CollectionViewSource x:Key="cvs" Source="{StaticResource personals}">
      <CollectionViewSource.GroupDescriptions>
        <data:PropertyGroupDescription PropertyName="Sex" />
      </CollectionViewSource.GroupDescriptions>
    </CollectionViewSource>
  </Window.Resources>
  <Grid>
    <StackPanel DataContext="{StaticResource cvs}">
      <ListBox x:Name="listbox1" ItemsSource="{Binding}">
        <ListBox.GroupStyle>
          <x:Static Member="GroupStyle.Default"/>
        </ListBox.GroupStyle>
        <ListBox.ItemTemplate>
          <DataTemplate>
            <StackPanel Orientation="Horizontal">
              <TextBlock Text="{Binding Path=Name}" />
              <TextBlock>,</TextBlock>
              <TextBlock Text="{Binding Path=Age}" />
              <TextBlock>,</TextBlock>
              <TextBlock Text="{Binding Path=Sex}" />
            </StackPanel>
          </DataTemplate>
        </ListBox.ItemTemplate>
      </ListBox>
    </StackPanel>
  </Grid>
</Window>

注意引入 xmlns:data="clr-namespace:System.Windows.Data;assembly=PresentationFramework" 命名空間。

(3) 過濾

利用 CollectionViewSource.Filter 委托屬性,我們可以對數據源做出過濾處理。比如過濾掉全部女性。

Window1.xaml.cs

public partial class Window1 : Window
{
  public Window1()
  {
    InitializeComponent();
    var personals = this.FindResource("personals");
    var view = CollectionViewSource.GetDefaultView(personals);
    view.Filter = o => 
    {
      return (o as Personal).Sex != Sex.Female;
    };
  }
}

(MSDN 文檔好像對不上)

(4) 導航

這個功能很常用,尤其是在數據庫系統開發中。不過需要注意的是我們必須確保 IsSynchronizedWithCurrentItem = true。

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="15" Sex="Male" />
      <my:Personal Name="Mary" Age="11" Sex="Female" />
      <my:Personal Name="Jack" Age="12" Sex="Male" />
      <my:Personal Name="Smith" Age="10" Sex="Male" />
      <my:Personal Name="Li." Age="8" Sex="Female" />
    </my:PersonalList>
  </Window.Resources>
  <Grid>
    <StackPanel DataContext="{StaticResource personals}">
      <ListBox x:Name="listbox1" ItemsSource="{Binding}" IsSynchronizedWithCurrentItem="True" >
        <ListBox.ItemTemplate>
          <DataTemplate>
            <StackPanel Orientation="Horizontal">
              <TextBlock Text="{Binding Path=Name}" />
              <TextBlock>,</TextBlock>
              <TextBlock Text="{Binding Path=Age}" />
              <TextBlock>,</TextBlock>
              <TextBlock Text="{Binding Path=Sex}" />
            </StackPanel>
          </DataTemplate>
        </ListBox.ItemTemplate>
      </ListBox>
      <Label Content="{Binding /Name}" />
      <Label Content="{Binding /Age}"/>
      <Button x:Name="btnFirst" Click="ButtonClick" Content="First" />
      <Button x:Name="btnPrev" Click="ButtonClick" Content="Prev" />
      <Button x:Name="btnNext" Click="ButtonClick" Content="Next" />
      <Button x:Name="btnLast" Click="ButtonClick" Content="Last" />
      <Button x:Name="btnPostion" Click="ButtonClick" Content="Position: 2" Tag="2" />
    </StackPanel>
  </Grid>
</Window>

Window1.xaml.cs

public partial class Window1 : Window
{
  public Window1()
  {
    InitializeComponent();
  }
  protected void ButtonClick(object sender, RoutedEventArgs e)
  {
    var personals = this.FindResource("personals") as PersonalList;
    var view = CollectionViewSource.GetDefaultView(personals);
    if (sender == btnFirst)
      view.MoveCurrentToFirst();
    else if (sender == btnPrev && view.CurrentPosition > 0)
      view.MoveCurrentToPrevious();
    else if (sender == btnNext && view.CurrentPosition < personals.Count - 1)
      view.MoveCurrentToNext();
    else if (sender == btnLast)
      view.MoveCurrentToLast();
    else if (sender == btnPostion)
      view.MoveCurrentToPosition(Convert.ToInt32(btnPostion.Tag));
  }
}

這很有趣,或許你也注意到了 Label 的 Binding 語法。

<Label Content="{Binding /}" /> 表示綁定到當前選擇項。
<Label Content="{Binding /Name}" /> 表示綁定到當前選擇項的 Name 屬性。

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