Reputation: 581
My program has two ListBoxes. They exchange their items each other by Add
and Remove
buttons. During the addition and the removal, I'd like to sort the items (by the IDs), using OrderBy
, but I don't know how to use this query result. How can I use OrderBy
in my case?
It seems that OrderBy
is working, but I just don't know where to put:
IEnumerable<GraphViewModel> query_orderBy_ID = RightListBoxItems.OrderBy(value => value.ID);
??? = query_orderBy_ID;
... OK, then I took the right-hand side and put it back into the original collection:
RightListBoxItems = (ObservableCollection<GraphViewModel>)RightListBoxItems.OrderBy(value => value.ID).ToList();
error CS0030: Cannot convert type 'System.Collections.Generic.List' to 'System.Collections.ObjectModel.ObservableCollection'
I thought that casting would solve this problem, but it doesn't work.
Here is my code:
MainWindow.xaml.cs
EDITED: Added a query_orderBy_ID
loop in Add_Button_Click()
and made it simpler, sorry:
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);
}
}
The main purpose of this question is to sort my ListBoxes, so the ListBox items should be sorted in the right order [T0
, T1
, T2
]. I believe they will be sorted, if the above problem is solved.
Any suggestion would be helpful. Thank you.
Upvotes: 0
Views: 301
Reputation: 28968
OrderBy
will return a IOrderedEnumerable<T>
which is sorted according to the sort key. The original collection remains in its original state. You therefore need to overwrite the original collection with the sorted result collection:
this.LeftListBoxItems = new ObservableCollection<GraphViewModel>(this.LeftListBoxItems.OrderBy(value => value.ID))
To have the ObservableCollection
sort automatically when adding/removing items, you can configure it once (e.g., from the constructor) by adding a SortDescription
to the ICollectionView
:
CollectionViewSource.GetDefaultView(this.LeftListBoxItems)
.SortDescriptions
.Add(new SortDescription(nameof(GraphViewModel.ID), ListSortDirection.Ascending));
Note
WPF is binding to the ICollectionView
of a collection rather than to the collection directly. Setting the SortDescription
on a ICollectionView
will only sort this ICollectionView
. This means the UI appears sorted whereas the underlying collection remains unsorted (or sorted by different rules).
Upvotes: 2