我不能仅使用XAML对WPF ListBox进行排序

时间:2014-05-24 14:39:18

标签: c# wpf xaml sorting listbox

我无法在XAML中对WPF ListBox进行排序。我看过帖子了 How can I sort a ListBox using only XAML and no code-behind?但它没有帮助我。我想通过Title字段上升来对lbxBooks ListBox(显示详细数据,参见下面的XAML)进行排序。这是此ListBox描述的XAML:

<Window x:Class="BookCatalogue.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" WindowStartupLocation="CenterScreen">
    <Window.Resources>
        <!--This XMLDataProvider uses file Books.xml as data source 
        and executes (via XPath property) data query from Category nodes in this file.-->
        <XmlDataProvider x:Key="MyList" Source="Data\Books.xml"
                       XPath="Books/Category"/>
        <!--This is data template for ListBox that shows master-level data-->
        <DataTemplate x:Key="masterDataTemplate">
            <TextBlock Text="{Binding XPath=@name}" />
        </DataTemplate>
        <!--This is data template for ListBox that shows detail-level data-->
        <DataTemplate x:Key="detailDataTemplate">
          <StackPanel>
             <TextBlock Text="{Binding XPath=Cover}"/>
             <TextBlock Text="{Binding XPath=Title}" Margin="0,0,0,10"/>  <!--This is title of book-->
             <TextBlock Text="{Binding XPath=Author}" Margin="0,0,0,10"/>
             <TextBlock Text="{Binding XPath=Published}" Margin="0,0,0,10"/>
          </StackPanel>
        </DataTemplate>
    </Window.Resources>
    <!--Grid for window mark up-->
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <!--This ListBox shows master-level data-->
      <ListBox Name="lbxCategory" Grid.Row="0" Grid.Column="0" ItemsSource="{Binding Source=
{StaticResource MyList}}"
                   ItemTemplate="{StaticResource masterDataTemplate}" 
IsSynchronizedWithCurrentItem="true"/>
        <!--This ListBox must show details-level data. It must be sorted by ascent by Title (title of the book)-->
      <ListBox Name="lbxBooks" Grid.Row="1" Grid.Column="0" ItemsSource="{Binding 
ElementName=lbxCategory, Path=SelectedItem.ChildNodes}"
               ItemTemplate="{StaticResource detailDataTemplate}" 
IsSynchronizedWithCurrentItem="True"/>
    </Grid>
</Window>

以下XML文件用作数据源。标题节点在此处注释为“这是书的标题”:

<?xml version="1.0" encoding="utf-8" ?>
<Books xmlns="">
  <Category name="Computer Programming">
    <Book>
      <Author>H. Schildt</Author>
      <Title>C# 4.0 The Complete Reference</Title>  <!--This is title of book-->
      <Published>2011</Published>
      <Categ>Computer Programming</Categ>
    </Book>
    <Book>
      <Author>I. Abramson</Author>
      <Title>Oracle Database 10g. A Beginner's Guide</Title>  <!--This is title of book-->
      <Published>2004</Published>
      <Categ>Computer Programming</Categ>
    </Book>
  </Category>
  <Category name="Art Editions">
    <Book>
      <Author>M. Cervantes</Author>
      <Title>The Ingenious Gentleman Don Quixote of La Mancha </Title>  <!--This is title of book-->
      <Published>1997</Published>
      <Categ>Art Editions</Categ>
    </Book>
    <Book>
      <Author>P. Ronsard</Author>
      <Title>Les Amours</Title>
      <Published>1997</Published>
      <Categ>Art Editions</Categ>
    </Book>
  </Category>
</Books>

如何按标题(书名)上升按lbxBooks ListBox排序。我该怎么办?

1 个答案:

答案 0 :(得分:1)

不是一个非常优雅的解决方案,但至少它有效。在您的Xaml中添加另一个绑定到书籍的XmlDataProvider和一个用于过滤和排序的集合视图。

这是你的Xaml:

<Window x:Class="BookCatalogue.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
        WindowStartupLocation="CenterScreen"
        Title="MainWindow" Height="350" Width="525">

    <Window.Resources>
        <!--This XMLDataProvider uses file Books.xml as data source 
        and executes (via XPath property) data query from Category nodes in this file.-->
        <XmlDataProvider x:Key="MyList" Source="Data\Books.xml" XPath="Books/Category"/>
        <XmlDataProvider x:Key="MySubList" Source="Data\Books.xml" XPath="Books/Category/Book"/>

        <!--This is data template for ListBox that shows master-level data-->
        <DataTemplate x:Key="masterDataTemplate">
            <TextBlock Text="{Binding XPath=@name}" />
        </DataTemplate>
        <!--This is data template for ListBox that shows detail-level data-->
        <DataTemplate x:Key="detailDataTemplate">
            <StackPanel>
                <TextBlock Text="{Binding XPath=Cover}"  Margin="0,0,0,2"/>
                <TextBlock Text="{Binding XPath=Title}" Margin="0,0,0,2"/>
                <!--This is title of book-->
                <TextBlock Text="{Binding XPath=Author}" Margin="0,0,0,2"/>
                <TextBlock Text="{Binding XPath=Published}" Margin="0,0,0,10"/>
            </StackPanel>
        </DataTemplate>

        <CollectionViewSource x:Key="SortedList" Source="{StaticResource MySubList}" Filter="CollectionViewSource_Filter_1" IsLiveFilteringRequested="True">
            <CollectionViewSource.SortDescriptions>
                <scm:SortDescription PropertyName="Title"/>
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>

    </Window.Resources>
    <!--Grid for window mark up-->
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>
        <!--This ListBox shows master-level data-->
        <ListBox Name="lbxCategory" Grid.Row="0" Grid.Column="0" 
                 ItemsSource="{Binding Source={StaticResource MyList}}"
                 ItemTemplate="{StaticResource masterDataTemplate}" 
                 IsSynchronizedWithCurrentItem="true" 
                 SelectionChanged="lbxCategory_SelectionChanged_1"/>

        <!--This ListBox must show details-level data. It must be sorted by ascent by Title (title of the book)-->
        <ListBox Name="lbxBooks" Grid.Row="1" Grid.Column="0" 
               ItemsSource="{Binding Source={StaticResource SortedList}}"
               ItemTemplate="{StaticResource detailDataTemplate}" 
               IsSynchronizedWithCurrentItem="True"/>

    </Grid>
</Window>

并将这些方法添加到您的代码中。

private void lbxCategory_SelectionChanged_1(object sender, SelectionChangedEventArgs e)
{
    lbxBooks.Items.Refresh();
    CollectionViewSource collectionView = Resources["SortedList"] as CollectionViewSource;
    if(collectionView.View != null) collectionView.View.Refresh();
}

private void CollectionViewSource_Filter_1(object sender, FilterEventArgs e)
{
    XmlElement element = e.Item as XmlElement;
    e.Accepted = ((XmlElement)lbxCategory.SelectedItem).Attributes["name"].Value == element.ParentNode.Attributes["name"].Value;
}