WPF Sorting an ObservableCollection de-selects a ComboBox

拟墨画扇 提交于 2019-12-18 09:39:30

问题


I have a ComboBox where a user can select what JobType they are working on. The ComboBox has a list of AllJobTypes. The problem stems from when a user adds a new JobType, I add the JobType to the AllJobTypes ObservableCollection, then sort it. When the sorting happens the ComboBox get's de-selected and not really sure why. The JobConfig.SelectedJobType.Name never changes in this process. Is there a way to sort an observable collection where it doesn't break the ComboBox?

public class JobTypeList : ObservableCollection<JobType> {

  public void SortJobTypes() {
    var sortableList = new List<JobType>(this);
    sortableList.Sort((x, y) => x.Name.CompareTo(y.Name));
    //this works but it creates a bug in the select for JobTypes
    for (int i = 0; i < sortableList.Count; i++) {
        this.Move(this.IndexOf(sortableList[i]), i);
    }
  }

And in the XAML

<ComboBox Grid.Column="0" SelectionChanged="JobTypeComboBox_SelectionChanged"
                              Name="JobTypeComboBox"
                              ItemsSource="{Binding Path=AllJobTypes}"
                              DisplayMemberPath="Name"
                              SelectedValuePath="Name"
                              SelectedValue="{Binding 
Path=JobConfig.SelectedJobType.Name}" />

回答1:


Instead of sorting the collection in the view model, you should bind the ComboBox's ItemsSource to a CollectionViewSource, where you can specify a SortDescription:

<Window ...
    xmlns:scm="clr-namespace:System.ComponentModel;assembly=WindowsBase"
    ...>
    <Window.Resources>
        <CollectionViewSource x:Key="cvs" Source="{Binding AllJobTypes}">
            <CollectionViewSource.SortDescriptions>
                <scm:SortDescription PropertyName="Name"/>
            </CollectionViewSource.SortDescriptions>
        </CollectionViewSource>
    </Window.Resources>

    ...
    <ComboBox ItemsSource="{Binding Source={StaticResource cvs}}"
              DisplayMemberPath="Name"
              SelectedValuePath="Name"
              SelectedValue="{Binding JobConfig.SelectedJobType.Name}"/>
    ...

</Window>

For further information see How to: Sort and Group Data Using a View in XAML




回答2:


Here's a version using ItemsSource/SelectedItem. Note that you can add a new item to the list and sort it without losing the currently selected item in the view.

The window

<Window
    x:Class="SortingAList.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:SortingAList"
    mc:Ignorable="d"
    Title="MainWindow"
    Height="350"
    Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition />
            <RowDefinition />
        </Grid.RowDefinitions>
        <TextBox
            Text="{Binding NewJobType, Delay=1000}"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Width="200" />
        <ComboBox
            Grid.Row="1"
            ItemsSource="{Binding JobTypes}"
            SelectedItem="{Binding SelectedJobType}"
            DisplayMemberPath="Name"
            HorizontalAlignment="Center"
            VerticalAlignment="Center"
            Width="200" />
    </Grid>
</Window>

The code

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        DataContext = new ViewModel();
    }
}

public class Notifier : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;
    protected void Notify([CallerMemberName]string property = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
    }
}

public class ViewModel : Notifier
{
    private JobType _selectedJobType;
    private string _newJobType;

    public JobTypeList JobTypes { get; private set; } 
    public JobType SelectedJobType { get => _selectedJobType; set { _selectedJobType = value; Notify(); } }
    public string NewJobType { get => _newJobType; set { _newJobType = value; Notify(); AddNewJobType(value); } }
    public ViewModel()
    {
        JobTypes = new JobTypeList();
        JobTypes.Add(new JobType { Name = "Butcher" });
        JobTypes.Add(new JobType { Name = "Baker" });
        JobTypes.Add(new JobType { Name = "LED maker" });
    }

    private void AddNewJobType(string name)
    {
        if(JobTypes.Any(x => x.Name == name)) return;
        JobTypes.Add(new JobType { Name = name });
        JobTypes.SortJobTypes();
    }
}
public class JobType : Notifier
{
    private string _name;

    public string Name { get => _name; set { _name = value; Notify(); } }
}

Using your JobTypesList

public class JobTypeList : ObservableCollection<JobType>
{

    public void SortJobTypes()
    {
        var sortableList = new List<JobType>(this);
        sortableList.Sort((x, y) => x.Name.CompareTo(y.Name));
        //this works but it creates a bug in the select for JobTypes
        for(int i = 0; i < sortableList.Count; i++)
        {
            this.Move(this.IndexOf(sortableList[i]), i);
        }
    }
}


来源:https://stackoverflow.com/questions/47696868/wpf-sorting-an-observablecollection-de-selects-a-combobox

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!