/ / Sort ObservableCollection według jego właściwości - wpf, sortowanie, observablecollection

Sortuj ObservableCollection zgodnie z jego właściwością - wpf, sortowanie, observablecollection

Wiem, że już o to pytano, ale nadalnie mogę owinąć głowy jakimkolwiek rozwiązaniem, które zadziała w mojej sprawie. Chcę móc posortować obserwowalną kolekcję w tym projekcie według nazwy elementu. Oto pełny projekt https://gist.github.com/NewCoderNotInTown/322274bd7d2fd57bf2ae7784e1315b73.

celem jest posortowanie obu list, oryginalnej i skopiowanej, posortowanych alfabetycznie.

docenić rozwiązanie dla tej sprawy. tak proste, jak to możliwe dla początkującego.

I Edytuj pytanie z pełnym kodem zgodnie z zaleceniami.

Kod dla 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>

Kod dla 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;
}
}
}

Kod dla 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>

Kod dla 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();
}
}
}

Kod dla 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>

Kod dla 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();
}
}
}

Kod dla 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));
}
}
}

Kod dla 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;
}
}
}

Kod 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);
}
}
}

Kod dla 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>();

}
}

Odpowiedzi:

1 dla odpowiedzi № 1

Oto trzy typowe sposoby sortowania kodu.

  1. Ręcznie zastosuj opcję Sortuj za każdym razem, gdy dodasz elementy. Sugerowałbym linq do faktycznego sortowania, chociaż możesz zbudować własny. W twoim konkretnym przypadku wyglądałoby to tak:

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

    Zakłada się, że włączasz seter tak MyItems nie jest tylko do odczytu.

  2. W getterze dla MyItems, zwróć kolekcję posortowaną (i użyj kopii zapasowejwłaściwość dla niego). To nie jest naprawdę idealne, ponieważ budujesz posortowaną kolekcję dla każdego połączenia wykonanego do gettera. Twój kod wyglądałby tak:

    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. (Zalecane) Praca z CollectionViewSource, który znajduje się na szczycie Twojej kolekcji i stosuje operacje przyjazne dla interfejsu użytkownika, takie jak sortowanie i filtrowanie.

    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; }}
    

    }

    A potem po prostu się połącz MyItemsSorted zamiast MyItems


0 dla odpowiedzi nr 2

Możesz to zrobić za pomocą LINQ, ale będziesz musiałwywołaj Sort (), gdy skończysz dodawanie lub usuwanie elementów. Jeśli zdarza się to często w przypadku dużych list, możesz zajrzeć do ObservableCollection.Insert i użyć własnego programu porównującego.

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);
}
}