wpf 绑定到列表的ComboBox< Class>未在下拉列表中排序,但在列表排序时使用箭头键正确排序

ovfsdjhp  于 2022-11-18  发布在  其他
关注(0)|答案(3)|浏览(251)

我的 MainWindow.xaml 中有一个绑定到List<Job>的ComboBox控件,其中Job是一个具有多个属性并实现INotifyPropertyChangeIComparable的类MainWindow类也实现了INotifyPropertyChange。当我从数据库加载这个列表时,已正确填充绑定的ComboBox控件。ComboBox控件在xaml中定义为

<ComboBox x:Name="JobsComboBox" ItemsSource = "{Binding Path=AllJobs, Mode=TwoWay}" IsSynchronizedWithCurrentItem="True" 
                  ScrollViewer.VerticalScrollBarVisibility="Auto" MaxHeight="400" 
                  MaxWidth="400" HorizontalContentAlignment="Center" />

我有一个单独的控件,允许用户按Job的特定属性排序。当用户选择不同的排序属性时,我使用delegate对列表排序并通知更改,如下所示:

public void SortJobsListByProperty(string? propertyName)
    {
        if (AllJobs != null) AllJobs.Sort(delegate(Job x, Job y)
        {
            int result = 0;

            switch (propertyName)
            {
                case "Quantity":
                    result = x.Quantity.CompareTo(y.Quantity);
                    break;
                case "Due Date":
                    result = x.DueDate.CompareTo(y.DueDate);
                    break;
                case "Siemens PN":
                    result = x.Assembly.SiemensPN.CompareTo(y.Assembly.SiemensPN);
                    break;
                case "Customer PN":
                    result = x.Assembly.CustomerPN.CompareTo(y.Assembly.CustomerPN);
                    break;
                default:
                    result = x.JobNumber.CompareTo(y.JobNumber);
                    break;
            }
            return result;
        });
        NotifyPropertyChange("AllJobs");
    }

奇怪的是:如果ComboBox具有键盘焦点,我可以使用上/下箭头键在项目之间导航,并且选定的项目具有正确的排序顺序。但是,如果我单击ComboBox上的下拉箭头,则显示的列表不具有正确的顺序。但显示的顺序与最初加载列表时的顺序相同,就好像选定项的索引遵循排序,但显示的下拉列表没有更新。
我到处寻找其他有类似问题的线程,但没有找到。我找到的最接近的解决方案是,如果集合需要排序到ComboBox中,应该使用ObservableCollection而不是List<Class>。但我不知道如何排序ObservableCollection,我觉得下拉列表中的顺序应该与箭头键导航相匹配。控件显然看到了列表的更改,或者箭头键无法按我所理解的正确顺序导航。我不熟悉数据绑定和属性更改通知,因此如果遗漏了一些明显的信息,我表示歉意。如果格式不正确或不清楚,我也表示歉意,我可以尝试澄清。提前感谢您的帮助!
编辑:我还注意到,如果我使用下拉菜单选择ListItem,当前项实际上是正确的项,只是组合框选择中的字符串不正确。例如,如果我通过箭头键或下拉菜单选择导航到ListBox中的第三项,则当前项实际上是当前排序顺序中的第三项。但其属性与ToString不匹配()方法。第三个JobNumber是123456,下拉列表中的第三个项目是123456,但根据原始排序,为该选择显示的字符串包含一些其他JobNumber,如666666。看起来ComboBox实际上做出了正确的选择,但其字符串不匹配。

z5btuh9x

z5btuh9x1#

好了,在做了很多有希望的修正之后,我终于找到了有效的方法。显然,当绑定列表的排序顺序改变时,ComboBox项并不更新。相反,ComboBox的底层Items属性必须刷新。所以,在对绑定的List<Job>进行排序之后,我简单地将**JobsComboBox.Items.Refresh()**添加到SortJobsListByProperty(string)方法的底部。并且一切都像它应该的那样工作。ComboBox中的字符串被更新并与它们同步的当前项匹配。
希望这对将来与这个问题搏斗的人有帮助。

hmae6n7t

hmae6n7t2#

尽管您已经找到了适合您的解决方案,但我仍然提供了实现排序的其他解释和示例。
1.如果在数据级别(ViewModel)实现排序,则需要排序的不是列表本身,而是列表的表示形式。
这种排序仅适用于“固定”列表。列表中的更改(添加/删除/替换列表项,或更改列表项的属性)仅在下次“排序刷新”时考虑。
第一个
Implementation of the BaseInpc and RelayCommand classes.
1.如果你需要动态排序,那么你需要使用Observable Collection而不是列表,并且排序应该在View中使用CollectionView来实现。
CollectionView由ItemsControl类(包括列表框、组合框)的Items属性提供。
第一个

vof42yt1

vof42yt13#

稍微深入的回答/解释:
代码NotifyPropertyChange("AllJobs")正在通知所有监听器“该属性的值已更改”。但是,从技术上讲,它并没有更改。AllJobs属性仍然拥有相同的List<Job>示例。List<Job> * 内部 * 的某些内容已更改(项的顺序),但它仍然是同一个对象因此数据绑定框架获取NotifyPropertyChange调用,检查AllJobs的值,意识到现在存在的List<Job>与它已经拥有的List<Job>相同,然后假设所有内容都是最新的,将其保留在那里。它假设该对象内部没有任何内容发生更改,因为没有任何内容告诉它其他情况。
ObservableCollection<T>实现了INotifyCollectionChanged,这就是你告诉绑定系统“我的列表中的一个或多个元素已经改变,请更新它”的方式。
This answer实际上包含了您所需要的大部分内容。它为您提供了CollectionViewSource的“正确解决方案”,但也向您展示了如何对ObservableCollection<T>进行排序(如果您确实需要的话)(通过创建一个新的ObservableCollection<T>并使用LINQ的OrderBy)。

相关问题