对 ListBox 中的 ObservableCollection<Class> 数据进行排序
Posted
技术标签:
【中文标题】对 ListBox 中的 ObservableCollection<Class> 数据进行排序【英文标题】:Sorting ObservableCollection<Class> data in ListBox 【发布时间】:2020-03-19 17:31:27 【问题描述】:我的程序有两个 ListBox。他们通过Add
和Remove
按钮互相交换物品。在添加和删除期间,我想使用OrderBy
对项目进行排序(按ID),但我不知道如何使用此查询结果。在我的情况下如何使用OrderBy
?
似乎OrderBy
工作正常,但我就是不知道该放在哪里:
IEnumerable<GraphViewModel> query_orderBy_ID = RightListBoxItems.OrderBy(value => value.ID);
??? = query_orderBy_ID;
...好吧,那我把右手边拿回原来的集合里:
RightListBoxItems = (ObservableCollection<GraphViewModel>)RightListBoxItems.OrderBy(value => value.ID).ToList();
错误 CS0030:无法转换类型 'System.Collections.Generic.List' 到 'System.Collections.ObjectModel.ObservableCollection'
我认为强制转换可以解决这个问题,但它不起作用。
这是我的代码:
MainWindow.xaml.cs
已编辑:在Add_Button_Click()
中添加了一个query_orderBy_ID
循环并使其更简单,抱歉:
using Sorting_List_with_OrderBy.ViewModel;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows;
namespace Sorting_List_with_OrderBy
public partial class MainWindow : Window
public ObservableCollection<GraphViewModel> LeftListBoxItems get; set;
= new ObservableCollection<GraphViewModel>();
public ObservableCollection<GraphViewModel> RightListBoxItems get; set;
= new ObservableCollection<GraphViewModel>();
ObservableCollection<string> TestItems = new ObservableCollection<string>();
IEnumerable<GraphViewModel> query_orderBy_ID;
public MainWindow()
InitializeComponent();
DataContext = this;
TestItems.Add("T0");
TestItems.Add("T1");
TestItems.Add("T2");
foreach (var test in TestItems.Select((k, i) => new kvp = k, index = i ))
LeftListBoxItems.Add(new GraphViewModel(test.index, test.kvp));
private void Add_Button_Click(object sender, RoutedEventArgs e)
foreach (var graphViewModel in LeftListBox.SelectedItems.Cast<GraphViewModel>().ToList())
LeftListBoxItems.Remove(graphViewModel);
// 1st Attempt: I don't know where to put this result to ...
query_orderBy_ID = RightListBoxItems.OrderBy(value => value.ID);
// 2nd Attempt: This substitution fails ...
//RightListBoxItems = (ObservableCollection<GraphViewModel>)RightListBoxItems.OrderBy(value => value.ID).ToList();
RightListBoxItems.Add(graphViewModel);
query_orderBy_ID = RightListBoxItems.OrderBy(value => value.ID);
foreach (GraphViewModel orderBy_ID in query_orderBy_ID)
MessageBox.Show(orderBy_ID.ID + ": " + orderBy_ID.TestName);
private void Remove_Button_Click(object sender, RoutedEventArgs e)
foreach (var graphViewModel in RightListBox.SelectedItems.Cast<GraphViewModel>().ToList())
RightListBoxItems.Remove(graphViewModel);
LeftListBoxItems.Add(graphViewModel);
MainWindow.xaml
<Window x:Class="Sorting_List_with_OrderBy.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:local="clr-namespace:Sorting_List_with_OrderBy"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="600">
<Grid>
<ListBox Margin="15,158,0,69.8" x:Name="LeftListBox" HorizontalAlignment="Left" Width="184" Background="AntiqueWhite"
SelectionMode="Extended" ItemsSource="Binding LeftListBoxItems" DisplayMemberPath="TestName"/>
<Button x:Name="Add_Button" Height="26" Margin="232,196,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Width="80"
Click="Add_Button_Click" Content="Add >>"/>
<Button x:Name="Remove_Button" Margin="230,267,0,0" HorizontalAlignment="Left" VerticalAlignment="Top" Width="82"
Click="Remove_Button_Click" Height="26" Content="<< Remove"/>
<ListBox Margin="343,158,0,71.8" x:Name="RightListBox" HorizontalAlignment="Left" Width="200" Background="AntiqueWhite"
SelectionMode="Extended" ItemsSource="Binding RightListBoxItems" DisplayMemberPath="TestName"/>
</Grid>
</Window>
ViewModel/GraphViewModel.cs
namespace Sorting_List_with_OrderBy.ViewModel
public class GraphViewModel
public int ID get;
public string TestName get;
public GraphViewModel(int id, string testName) => (ID, TestName) = (id, testName);
这个问题的主要目的是对我的ListBoxes进行排序,所以ListBox项应该按照正确的顺序排序[T0
,T1
,T2
]。如果上面的问题解决了,我相信他们会被排序的。
任何建议都会有所帮助。谢谢。
【问题讨论】:
how to sort ObservableCollection的可能重复 【参考方案1】:OrderBy
将返回一个IOrderedEnumerable<T>
,它根据排序键排序。原始集合保持其原始状态。因此,您需要用排序结果集合覆盖原始集合:
this.LeftListBoxItems = new ObservableCollection<GraphViewModel>(this.LeftListBoxItems.OrderBy(value => value.ID))
要让ObservableCollection
在添加/删除项目时自动排序,您可以通过将SortDescription
添加到ICollectionView
来配置一次(例如,从构造函数中):
CollectionViewSource.GetDefaultView(this.LeftListBoxItems)
.SortDescriptions
.Add(new SortDescription(nameof(GraphViewModel.ID), ListSortDirection.Ascending));
注意
WPF 绑定到集合的ICollectionView
,而不是直接绑定到集合。在ICollectionView
上设置SortDescription
只会对ICollectionView
进行排序。这意味着 UI 显示为已排序,而基础集合保持未排序(或按不同规则排序)。
【讨论】:
第二个完美运行! (在ICollectionView
中添加SortDescription
)谢谢!但是,第一个无法编译(用排序结果集合覆盖原始集合)。因此,我将<string>
替换为<GraphViewModel>
并将行放在Add(graphViewModel)
之后,但有些项目消失了。抱歉,如果我的设置有误,但您可能想编辑第一个。再次,非常感谢!
感谢您的评论。我修复了 sn-p(我不知何故希望这是一个 string
集合,但没有考虑太多。我的错)。但是你说的“一些项目消失了”是什么意思?当使用SortDescription
?
对不起,“disappear”是错误的,但只能将一个项目移到右侧,然后永远不能移到另一侧。当用排序结果集合覆盖原始集合时会发生这种情况。我按以下顺序排列:LeftListBoxItems.Remove
-> this.LeftListBoxItems = ...
-> RightListBoxItems.Add
-> this.RightListBoxItems = ...
如果您愿意,可以尝试一下。无论如何,你的第二个工作完美,所以我可以继续。谢谢你帮助我!
好的,现在我明白了。这只是一次,因为视图没有收到有关新集合的通知。在这种情况下,不仅ObservableCollection
的内容发生了变化(由于排序),而且整个集合本身(引用)也被替换了。为了解决这个问题,您可以在MainWindow
上实现INotifyPropertyChanged
,或者将两个集合都实现为DependencyProperty
。考虑始终将控件上的公共属性设为DependencyProperty
。这样,当将新的集合实例分配给属性时,视图将收到通知并进行更新。
啊,我明白了。是的,它适用于INotifyPropertyChanged
。有一天我会尝试DependencyProperty
,因为我还不熟悉它。 ;-) 非常感谢!以上是关于对 ListBox 中的 ObservableCollection<Class> 数据进行排序的主要内容,如果未能解决你的问题,请参考以下文章
C# winform中关于两个ListBox清除selectIndex的问题。