当前位置: 首页 > 编程语言 > C#

在数据绑定到ComboBox中的CollectionViewSource时,如何保留CurrentItem的TwoWay绑定分享

时间:2023-04-10 13:22:39 C#

C#学习教程:ComboBox中数据绑定CollectionViewSource时如何保留CurrentItem的TwoWay绑定Observable{privatePersonm_Person=newPerson("Mike","Smith");privatereadonlyObservableCollectionm_AvailablePersons=newObservableCollection(newList{newPerson("Mike","Smith"),newPerson("Jake","Jackson"),});publicObservableCollectionAvailablePersons{get{返回m_AvailablePersons;}}publicPersonCurrentPerson{get{returnm_Person;}设置{m_Person=值;NotifyPropertyChanged("CurrentPerson");}}}成功数据绑定到ComboBox就足够了,例如:注意Person有Equals重载,当我在ViewModel中设置CurrentPerson值时,它会导致组合框当前项显示新值。现在假设我想使用CollectionViewSource向我的视图添加排序功能现在组合框项目源绑定将如下所示:它确实会被排序(如果我们添加更多明确的项目)。但是,当我们现在更改VM中的CurrentPerson时(在使用没有CollectionView的清晰绑定之前它工作正常),此更改不会显示在绑定的ComboBox中。我相信之后为了从VM设置CurrentItem,我们必须以某种方式访问??View(我们不在MVVM中从ViewModel查看View)并调用MoveCurrentTo方法来强制View显示currentItem更改。因此,通过添加额外的视图功能(排序),我们失去了对现有viewModel的TwoWay绑定,我认为这不是预期的行为。有没有办法在这里保留TwoWay绑定?也许我做错了什么。编辑:实际情况比我这样重写CurrentPersonsetter时可能出现的情况更复杂:第一的();}否则抛出新的ArgumentOutOfRangeException("value");NotifyPropertyChanged("CurrentPerson");它工作正常!这是有缺陷的行为,还是有解释?由于某些原因,即使重载了Equals,它也需要引用person对象的相等性。我真的不明白为什么它需要引用相等,所以我为可以解释为什么普通setter不起作用的人增加了悬赏,当重载Equal方法时,很明显可以看到“修复”的代码使用它有两个联合问题,但您已经强调了使用CollectionViewSource和ComboBox的真正问题。我仍在寻找以“更好的方式”解决此问题的替代方案,但您的setter修复程序有充分的理由避免了该问题。我已经完整地复制了您的示例,以确认问题和原因的理论。如果您使用SelectedValue而不是SelectedItem,则绑定到CurrentPerson的ComboBox将不会使用等号运算符来查找匹配项。如果你断开覆盖boolEquals(objectobj)你会发现当你改变选择时它不会被击中。通过将setter改成下面这样,你将使用Equals运算符来找到一个特定的匹配对象,所以可以使用后续的2个对象的值比较。设置{if(m_AvailablePersons.Contains(value)){m_Person=m_AvailablePersons.Where(p=>p.Equals(value)).First();}否则抛出新的ArgumentOutOfRangeException("value");NotifyPropertyChanged("CurrentPerson");现在真正有趣的结果是:即使您更改代码以使用SelectedItem,它也会很好地绑定到列表,但仍然不会绑定到排序视图!我将调试输出添加到Equals方法,即使找到匹配项,它们也会被忽略:publicoverrideboolEquals(objectobj){if(objisPerson){if(other.Firstname==Firstname&&other.Surname==Surname){Debug.WriteLine(string.Format("{0}=={1}",other.ToString(),this.ToString()));返回真;}else{Debug.WriteLine(string.Format("{0}{1}",other.ToString(),this.ToString()));返回假;}}返回base.Equals(obj);}我的结论......是ComboBox在幕后找到匹配项,但由于它与原始对象之间存在CollectionViewSource,因此它会忽略匹配项并比较对象(以决定选择哪个对象)。从内存中,CollectionViewSource自行管理当前选定的项目,因此如果您没有获得精确的对象匹配,则将CollectionViewSource与ComboxBox一起使用将不起作用。基本上,您的setter更改有效,因为它保证CollectionViewSource上的对象匹配,然后是ComboBox上的对象。测试代码对于那些想玩的人,完整的测试代码在下面(抱歉代码隐藏黑客,但这只是为了测试而不是MVVM)。只需要创建一个新的Silverlight4应用程序并添加这些文件/更改:PersonViewModel.csusingSystem;使用System.Collections.Generic;使用System.Collections.ObjectModel;使用System.ComponentModel;使用系统诊断;使用System.Linq;namespacePersonTests{publicclassPersonViewModel:INotifyPropertyChanged{privatePersonm_Person=null;privatereadonlyObservableCollectionm_AvailablePersons=newObservableCollection(newList{newPerson("Mike","Smith"),newPerson("Jake","Jackson"),newPerson("Anne","Aardvark"),});publicObservableCollectionAvailablePersons{get{返回m_AvailablePersons;}}publicPersonCurrentPerson{get{returnm_Person;}set{if(m_Person!=value){m_Person=value;NotifyPropertyChanged("CurrentPerson");}}//set//这有效//{//if(m_AvailablePersons.Contains(value)){//m_Person=m_AvailablePersons.Where(p=>p.Equals(value)).First();//}//否则抛出新的ArgumentOutOfRangeException("value");//否otifyPropertyChanged("CurrentPerson");//}}privatevoidNotifyPropertyChanged(stringname){if(PropertyChanged!=null){PropertyChanged(this,newPropertyChangedEventArgs(name));}}公共事件PropertyChangedEventHandlerPropertyChanged;}publicclassPerson{publicstringFirstname{get;放;}publicstring姓氏{get;放;}publicPerson(stringfirstname,stringsurname){this.Firstname=firstname;this.Surname=姓氏;}publicoverridestringToString(){returnFirstname+""+Surname;}publicoverrideboolEquals(objectobj){if(objisPerson){Personother=objasPerson;if(other.Firstname==Firstname&&other.Surname==Surname){Debug.WriteLine(string.Format("{0}=={1}",other.ToString(),this.ToString()));返回真;}else{Debug.WriteLine(string.Format("{0}{1}",other.ToString(),this.ToString()));返回假;}}返回base.Equals(obj);}}}MainPage.xaml中-->MainPage使用System.Windows;使用System.Windows.Controls;namespacePersonTests{publicpartialclassMainPage:UserControl{publicMainPage(){InitializeComponent();this.DataContext=newPersonViewModel();}privatevoidbutton1_Click(objectsender,RoutedEventArgse){(this.DataContextasPersonViewModel).CurrentPerson=newPerson("Mike","Smith");}privatevoidbutton2_Click(objectsender,RoutedEventArgse){(this.DataContextasPersonViewModel).CurrentPerson=newPerson("Anne","Aardvark");您是否考虑过使用CollectionView并在组合框中设置IsSynchronizedWithCurrentItem?这就是我所做的-而不是拥有你的CurrentPerson属性,你有collectionView.CurrentItem上的选定人员和collectionview上当前项目上的组合框我已经使用collectionview进行排序和分组没有任何问题-你得到一个很好的解耦来自这个的用户界面。我会将collectionview移动到代码并将其绑定到publicICollectionViewAvailablePersonsView{get;privateset;}inctor:AvailablePersonsView=CollectionViewSource.GetDefaultView(AvailablePersons)TwoWay绑定工作正常,但是当您从代码设置SelectedItem或选择SelectedIndex时,ComboBox不会在UI上自行更新。如果您需要此功能,只需扩展ComboBox并监听从Selector继承的SelectionChanged,或者如果您只想设置初始选择,则在Loaded中。我强烈推荐使用Microsoft的KyleMcClellan的ComboBoxExtensions。您可以在XAML中为ComboBox声明数据源-它在异步模式下更加灵活和可用。基本上解决方案主要是不对ComboBoxes使用CollectionViewSource。您可以对服务器端查询进行排序。以上是C#学习教程:数据绑定到ComboBox中的CollectionViewSource时,如何保留CurrentItem的TwoWay绑定共享的所有内容。如果对你有用,需要进一步了解C#学习教程,希望大家多加关注——本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。如需转载请注明出处: