根据ObservableCollection的属性对其进行排序

时间:2017-04-28 16:13:34

标签: wpf sorting observablecollection

我知道以前曾经问过这个问题,但仍然无法解决任何适合我案例的解决方案。我希望能够根据ItemName对此项目中的可观察集合进行排序。这是完整的项目https://gist.github.com/NewCoderNotInTown/322274bd7d2fd57bf2ae7784e1315b73

目的是让两个列表,原始列表和复制的列表按字母顺序排序。

欣赏这种情况的解决方案。对初学者来说尽可能简单。

我按照建议使用完整代码编辑问题。

MainWindow.xaml代码

<Window x:Class="TwoWindows.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:WB="clr-namespace:TwoWindows"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*"/>
        <RowDefinition Height="50"/>
    </Grid.RowDefinitions>
    <Button Grid.Row="1" Content="Click Me" Width="80" Height="25"  Click="ClickMe_Click"/>
    <TabControl Grid.Row="0" Margin="10">
        <TabItem>
            <TabItem.Header>
                <StackPanel>
                    <TextBlock Text="WindowB"/>
                </StackPanel>
            </TabItem.Header>
            <WB:WindowB x:Name="_windowB"/>
        </TabItem>
    </TabControl>
</Grid>

MainWindow.cs的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace TwoWindows
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void ClickMe_Click(object sender, RoutedEventArgs e)
    {
        var windowBViewModel = new WindowBViewModel("WindowB");
        var windowB = new WindowB();

        var windowAViewModel = new WindowAViewModel("WindowA", windowBViewModel);
        var windowA = new WindowA();

        windowA.DataContext = windowAViewModel;
        windowA.Show();

        _windowB.DataContext = windowBViewModel;
    }
   }
  }

WindowA.xaml的代码

<Window x:Class="TwoWindows.WindowA"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:TwoWindows"
    mc:Ignorable="d"
    Title="WindowA" Height="300" Width="600">
<Grid>
    <Label Content="{Binding PageTitle}" />
    <ListBox ItemsSource="{Binding MyItems}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <CheckBox Content="{Binding ItemName}" IsChecked="{Binding IsChecked}"/>
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</Grid>

WindowA.xaml.cs的代码

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Data;
  using System.Windows.Documents;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Imaging;
  using System.Windows.Shapes;

  namespace TwoWindows
  {
  public partial class WindowA : Window
  {
    public WindowA()
    {
        InitializeComponent();
    }
   }
}

WindowB.xaml的代码

<UserControl x:Class="TwoWindows.WindowB"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:TwoWindows"
    mc:Ignorable="d">
<Grid>
    <Label Content="{Binding PageTitle}" />
    <ListBox ItemsSource="{Binding MyItems}">
        <ListBox.ItemTemplate>
            <DataTemplate>
                <StackPanel Orientation="Horizontal">
                    <TextBlock Text="{Binding ItemName}" />
                </StackPanel>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
  </Grid>
</UserControl>

WindowB.xaml.cs的代码

  using System;
  using System.Collections.Generic;
  using System.Linq;
  using System.Text;
  using System.Threading.Tasks;
  using System.Windows;
  using System.Windows.Controls;
  using System.Windows.Data;
  using System.Windows.Documents;
  using System.Windows.Input;
  using System.Windows.Media;
  using System.Windows.Media.Imaging;
  using System.Windows.Shapes;

  namespace TwoWindows
{
public partial class WindowB : UserControl
{
    public WindowB()
    {
        InitializeComponent();
    }
   }
 }

WindowAViewModel.cs的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TwoWindows
{
public class WindowAViewModel : BaseWindowViewModel
{

    public WindowAViewModel(string pageTitle, WindowBViewModel windowBViewModel)
    {
        PageTitle = pageTitle;

        MyItems.Add(new MyCustomItemViewModel("Apple", windowBViewModel));
        MyItems.Add(new MyCustomItemViewModel("Orange", windowBViewModel));
        MyItems.Add(new MyCustomItemViewModel("Banana", windowBViewModel));
    }
  }
}

WindowBViewModel的代码

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TwoWindows
{
public class WindowBViewModel : BaseWindowViewModel
{
    public WindowBViewModel(string pageTitle)
    {
        PageTitle = pageTitle;
    }
   }
}

MyCustomItemViewModel.cs的代码

using PropertyChanged;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace TwoWindows
{
[ImplementPropertyChanged]
public class MyCustomItemViewModel
{
    public string ItemName { get; set; }
    public bool IsChecked { get; set; }
    public WindowBViewModel WindowBViewModelObj { get; set; }

    public MyCustomItemViewModel(string itemName, WindowBViewModel windowBViewModel)
    {
        ItemName = itemName;
        WindowBViewModelObj = windowBViewModel;
    }

    private void OnIsCheckedChanged()
    {
        if (IsChecked)
            WindowBViewModelObj.MyItems.Add(this);
        else
            WindowBViewModelObj.MyItems.Remove(this);
      }
   }
}

BaseWindowViewModel.cs的代码

 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;

namespace TwoWindows
{
public class BaseWindowViewModel
{
    public string PageTitle { get; set; }

    public ObservableCollection<MyCustomItemViewModel> MyItems { get; } = new ObservableCollection<MyCustomItemViewModel>();

  }
}

2 个答案:

答案 0 :(得分:1)

以下是从代码中排序的三种常用方法。

  1. 随时添加项目时手动应用排序。我会建议linq进行实际排序,尽管你可以建立自己的排序。在您的具体情况下,它看起来像这样:

    MyItems.Add(new MyCustomItemViewModel("Apple", windowBViewModel));
    MyItems.Add(new MyCustomItemViewModel("Orange", windowBViewModel));
    MyItems.Add(new MyCustomItemViewModel("Banana", windowBViewModel));
    
    MyItems = MyItems.Sort(p => p.ItemName);
    

    这假设您启用了设置器,因此MyItems不是只读的。

  2. MyItems的getter中,返回已排序的集合(并为其使用支持属性)。这不是很理想,因为您为每个对getter进行的调用构建了有序集合。对于您的代码,它看起来像这样:

    public class BaseWindowViewModel
    {
       public string PageTitle { get; set; }
    
       private ObservableCollection<MyCustomItemViewModel> _myItems = new ObservableCollection<MyCustomItemViewModel>()
       public ObservableCollection<MyCustomItemViewModel> MyItems 
       {
          get { return _myItems.Sort(p => p.ItemName); }
       }
     }
    
  3. (推荐)使用位于集合顶部的CollectionViewSource,并应用类似于排序和过滤的UI友好操作。

    public class BaseWindowViewModel
    {
       public string PageTitle { get; set; }
    
       private ObservableCollection<MyCustomItemViewModel> _myItems;
       public ObservableCollection<MyCustomItemViewModel> MyItems 
       {
          get 
          {
               if (_myItems == null)
               {
                   _myItems = new ObservableCollection<MyCustomItemViewModel>();
                   _myItemsSorted = CollectionViewSource.GetDefaultView(_myItems)
                   _myItemsSorted.SortDescriptions.Add(new SortDescription() { PropertyName = "ItemName" });
               }
               return _myItems; 
           }
       }
    
    private ICollectionView _myItemsSorted;
    public ICollectionView MyItemsSorted { get { return _myItemsSorted; }}
    

    }

    然后只绑定到MyItemsSorted而不是MyItems

答案 1 :(得分:0)

您可以使用LINQ执行此操作,但在添加或删除项目时,您必须调用Sort()。如果大型列表发生了很多,您可能需要查看ObservableCollection.Insert并使用自己的比较器。

public class BaseWindowViewModel
{
    public string PageTitle { get; set; }

    public ObservableCollection<MyCustomItemViewModel> MyItems
    {
        get
        {
            return _MyItems;
        }
    }
    private ObservableCollection<MyCustomItemViewModel> _MyItems = new ObservableCollection<MyCustomItemViewModel>();

    public void Sort()
    {
        _MyItems = new ObservableCollection<MyCustomItemViewModel>(from i in _MyItems orderby i.ItemName select i);
    }
}