六、排序
如果想以特定的方式對資料進行排序,可以繫結到 CollectionViewSource,而不是直接繫結到 ObjectDataProvider。CollectionViewSource 則會成為資料來源,並充當擷取 ObjectDataProvider 中的資料的媒介,並提供排序、分組和篩選功能,然後將它傳送到目標。
這個顯示是使用 CollectionViewSource做為排序的資料來源,首先將CollectionViewSource的Source 屬性設定為 ObjectDataProvider的資源名稱。然後通過設定CollectionViewSource.SortDescriptions屬性,指定排序欄位和排序順序:
<CollectionViewSource x:Key="studentsView" Source="{Binding Source={StaticResource students}}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Name" Direction="Ascending" />
<scm:SortDescription PropertyName="Age" Direction="Descending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
WPF中的DataContext屬性是非常有用的,如果你有多個控制元件需要繫結同一個資料來源,那麼按照WinForm中的做法是給每個控制元件都繫結一次資料來源,那麼做重複程式碼就會很多。而在WPF中你可以首先把這些需要繫結同一個資料來源的控制元件放在同一個容器控制元件內,然後將容器控制元件的 DataContext 設定為繫結源,容器內的控制元件的資料來源繫結就可以不必再繫結,使用容器的資料來源。例如,下面
的示例:StackPanel的 DataContext 屬性繫結了資料來源,DataGrid就可以不必再次繫結了,直接使用StackPanel繫結的資料來源。
<StackPanel DataContext="{StaticResource studentsView}">
<TextBlock Width="248" Height="24" Text="資料排序:"
TextWrapping="Wrap"/>
<DataGrid AutoGenerateColumns="False"
ItemsSource="{Binding}" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="名稱" />
<DataGridTextColumn Binding="{Binding Age}" Header="年齡" />
<DataGridTextColumn Binding="{Binding Country}" Header="國家" />
<DataGridTextColumn Binding="{Binding Birthday}" Header="出生日期" />
</DataGrid.Columns>
</DataGrid>
</StackPanel>
如果該容器沒有定義 DataContext,那麼它會繼續查詢下一個外部巢狀容器,直到它找到當前的 DataContext 為止。如下圖所示。當點選列頭時,資料就會進行順序或逆序排序。如下圖。
整個示例的全部程式碼如下:
<Window x:Class="WpfApp1.WindowBindData"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApp1.Services"
xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
Title="WindowBindData" Height="700" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="150"/>
<RowDefinition Height="140"/>
<RowDefinition Height="100*"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<TextBlock Width="248" Height="24" Text="股票名稱:"
TextWrapping="Wrap"/>
<ListBox x:Name="listStockName" Width="248" Height="56">
<ListBoxItem Content="全通教育"/>
<ListBoxItem Content="大智慧"/>
<ListBoxItem Content="寶鋼股份"/>
<ListBoxItem Content="浦發銀行"/>
<ListBoxItem Content="工商銀行"/>
<ListBoxItem Content="中國建築"/>
<ListBoxItem Content="中國南車"/>
</ListBox>
<TextBlock Width="248" Height="24" Text="你所選中的股票名稱:" />
<TextBlock Width="248" Height="24" Text="{Binding ElementName=listStockName, Path=SelectedItem.Content}">
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="1">
<TextBlock Width="248" Height="24" Text="顏色:"
TextWrapping="Wrap"/>
<ListBox x:Name="listColor" Width="248" Height="56">
<ListBoxItem Content="Blue"/>
<ListBoxItem Content="Red"/>
<ListBoxItem Content="Green"/>
<ListBoxItem Content="Gray"/>
<ListBoxItem Content="Cyan"/>
<ListBoxItem Content="GreenYellow"/>
<ListBoxItem Content="Orange"/>
</ListBox>
<TextBlock Width="248" Height="24" Text="改變背景色:" />
<TextBlock Width="248" Height="24" Text="{Binding ElementName=listColor, Path=SelectedItem.Content, Mode=OneWay}"
Background="{Binding ElementName=listColor, Path=SelectedItem.Content, Mode=OneWay}">
</TextBlock>
<TextBox Name="txtTwoWay" Text="{Binding ElementName=listColor,Path=SelectedItem.Content,Mode=TwoWay}"
Background="{Binding ElementName=listColor,Path=SelectedItem.Content,Mode=TwoWay}"></TextBox>
</StackPanel>
<StackPanel Grid.Row="2">
<StackPanel.Resources>
<XmlDataProvider x:Key="MyColors" Source="Colors.xml" XPath="colors">
</XmlDataProvider>
</StackPanel.Resources>
<TextBlock Width="248" Height="24" Text="XML資料繫結:"
TextWrapping="Wrap"/>
<ListBox x:Name="listXmlColor" Width="248" Height="56" IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Source={StaticResource MyColors},XPath=color/@name}">
</ListBox>
<TextBlock Width="248" Height="24" Text="選中的顏色:" />
<TextBlock Width="248" Height="24" Text="{Binding ElementName=listXmlColor, Path=SelectedValue, Mode=OneWay}"
>
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="3">
<StackPanel.Resources>
<ObjectDataProvider x:Key="students" ObjectType="{x:Type local:StudentService}" MethodName="GetStudentList">
</ObjectDataProvider>
<DataTemplate x:Key="studentLayout" DataType="students">
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding Path=Name}"
FontWeight="Bold" Foreground="Blue"/>
<TextBlock Text=", "></TextBlock>
<TextBlock Text="{Binding Path=Age}"></TextBlock>
<TextBlock Text=", "></TextBlock>
<TextBlock Text="{Binding Path=Birthday}"></TextBlock>
<TextBlock Text=", "></TextBlock>
<TextBlock Text="{Binding Path=Country}"></TextBlock>
</StackPanel>
</DataTemplate>
<CollectionViewSource x:Key="studentsView" Source="{Binding Source={StaticResource students}}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="Name" Direction="Ascending" />
<scm:SortDescription PropertyName="Age" Direction="Descending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</StackPanel.Resources>
<TextBlock Width="248" Height="24" Text="物件資料繫結:"
TextWrapping="Wrap"/>
<ListBox x:Name="listObjectBind" Width="450" Height="80" IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding Source={StaticResource students}}"
ItemTemplate="{DynamicResource studentLayout}">
</ListBox>
<TextBlock Width="248" Height="24" Text="資料排序:"
TextWrapping="Wrap"/>
<DataGrid DataContext="{StaticResource studentsView}" AutoGenerateColumns="False"
ItemsSource="{Binding}" CanUserAddRows="False">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="名稱" />
<DataGridTextColumn Binding="{Binding Age}" Header="年齡" />
<DataGridTextColumn Binding="{Binding Country}" Header="國家" />
<DataGridTextColumn Binding="{Binding Birthday}" Header="出生日期" />
</DataGrid.Columns>
</DataGrid>
</StackPanel>
</Grid>
</Window>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace WpfApp1.Models
{
public class Student : DependencyObject
{
//宣告一個靜態只讀的DependencyProperty欄位
public static readonly DependencyProperty NameProperty;
public static readonly DependencyProperty AgeProperty;
public static readonly DependencyProperty BirthdayProperty;
public static readonly DependencyProperty CountryProperty;
static Student()
{
//註冊我們定義的依賴屬性Name,Age,birthday,Country
NameProperty = DependencyProperty.Register("Name", typeof(string), typeof(Student),
new PropertyMetadata("名稱", OnValueChanged));
AgeProperty = DependencyProperty.Register("Age", typeof(string), typeof(Student),
new PropertyMetadata("年齡", OnValueChanged));
BirthdayProperty = DependencyProperty.Register("Birthday", typeof(string), typeof(Student),
new PropertyMetadata("出生日期", OnValueChanged));
CountryProperty = DependencyProperty.Register("Country", typeof(string), typeof(Student),
new PropertyMetadata("國家", OnValueChanged));
}
private static void OnValueChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
//當值改變時,我們可以在此做一些邏輯處理
}
//屬性包裝器,通過它來讀取和設定我們剛才註冊的依賴屬性
public string Name
{
get { return (string)GetValue(NameProperty); }
set { SetValue(NameProperty, value); }
}
public string Age
{
get { return (string)GetValue(AgeProperty); }
set { SetValue(AgeProperty, value); }
}
public string Birthday
{
get { return (string)GetValue(BirthdayProperty); }
set { SetValue(BirthdayProperty, value); }
}
public string Country
{
get { return (string)GetValue(CountryProperty); }
set { SetValue(CountryProperty, value); }
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WpfApp1.Models;
namespace WpfApp1.Services
{
public class StudentService
{
public List<Student> GetStudentList()
{
Student liang = new Student();
liang.Age = "18";
liang.Name = "樑丘";
liang.Birthday = "1990-02-03";
liang.Country = "中國";
Student zuo = new Student();
zuo.Age = "22";
zuo.Name = "左丘";
zuo.Birthday = "1992-02-03";
zuo.Country = "中國";
Student diwu = new Student();
diwu.Age = "32";
diwu.Name = "第五言";
diwu.Birthday = "1982-11-03";
diwu.Country = "中國";
Student yang = new Student();
yang.Age = "12";
yang.Name = "羊舌微";
yang.Birthday = "2002-11-13";
yang.Country = "中國";
List<Student> personList = new List<Student>();
personList.Add(liang);
personList.Add(zuo);
personList.Add(diwu);
personList.Add(yang);
return personList;
}
}
}