/ / Ordina ObservableCollection secondo la sua proprietà - wpf, sorting, observablecollection

Ordina ObservableCollection in base alla sua proprietà: wpf, sorting, observablecollection

So che questo è stato chiesto prima, ma comunquenon riesco ad avvolgere la mia testa attorno a qualsiasi soluzione che funzioni per il mio caso. Voglio essere in grado di ordinare la collezione osservabile in questo progetto in base al ItemName. ecco il progetto completo https://gist.github.com/NewCoderNotInTown/322274bd7d2fd57bf2ae7784e1315b73.

lo scopo è di avere entrambi gli elenchi, quello originale e quello copiato, ordinati alfabeticamente.

apprezzare una soluzione per questo caso. il più semplice possibile per un principiante.

Modifica la domanda con il codice completo come consigliato.

Codice per 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>

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

Codice per 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>

Codice per 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();
}
}
}

Codice per 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>

Codice per 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();
}
}
}

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

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

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

Codice per 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>();

}
}

risposte:

1 per risposta № 1

Ecco tre modi comuni per ordinare dal tuo codice.

  1. Applica manualmente l'ordinamento ogni volta che aggiungi elementi. Suggerirei linq per l'ordinamento effettivo, anche se puoi costruirne uno tuo. Nel tuo caso specifico, sarebbe simile al seguente:

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

    Questo presuppone che tu abiliti il ​​setter così MyItems non è di sola lettura.

  2. Nel getter per MyItems, restituisce la raccolta ordinata (e utilizza un supportoproprietà per esso). Questo non è proprio l'ideale, dal momento che si crea la raccolta ordinata per ogni chiamata effettuata al getter. Per il tuo codice, sarebbe simile al seguente:

    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. (Consigliato) Lavora con CollectionViewSource che si trova in cima alla raccolta e applica operazioni compatibili con l'interfaccia utente come l'ordinamento e il filtro.

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

    }

    E poi si legano e basta MyItemsSorted piuttosto che MyItems


0 per risposta № 2

Puoi farlo usando LINQ, ma dovrai farlochiama Sort () quando hai finito di aggiungere o rimuovere elementi. Se ciò accade molto con elenchi di grandi dimensioni, potresti voler esaminare ObservableCollection.Insert e usare il tuo comparatore.

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