WPF MVVMcomboboxSelectedItem或SelectedValue无法正常工作
更新
经过一番调查。 什么似乎是问题是SelectedValue / SelectedItem发生在项目源完成加载之前。 如果我坐在一个rest点,等待几秒钟,按预期工作。 不知道我怎么去解决这个问题。
结束更新
我有一个应用程序在WPF中使用MVVM与ComboBox。 以下是ViewModel示例。 我遇到的问题是当我们离开我们的页面并迁移回ComboBox不select当前选定的值。
查看模型
public class MyViewModel { private MyObject _selectedObject; private Collection<Object2> _objects; private IModel _model; public MyViewModel(IModel model) { _model = model; _objects = _model.GetObjects(); } public Collection<MyObject> Objects { get { return _objects; } private set { _objects = value; } } public MyObject SelectedObject { get { return _selectedObject; } set { _selectedObject = value; } } }
为了这个例子,让我们说MyObject有两个属性(文本和Id)。 我的combobox的XAML看起来像这样。
XAML
<ComboBox Name="MyComboBox" Height="23" Width="auto" SelectedItem="{Binding Path=SelectedObject,Mode=TwoWay}" ItemsSource="{Binding Objects}" DisplayMemberPath="Text" SelectedValuePath="Id">
无论采用哪种方式,当我回到页面并重新组装对象时,ComboBox将不会select该值。 该对象通过get属性返回正确的对象。
我不确定这是否只是ComboBox和MVVM模式的工作方式的问题。 我们正在做的文本框绑定工作正常。
你有没有尝试在viewmodel中实现INotifyPropertyChanged
,然后在SelectedItem
被设置时引发PropertyChanged
事件?
如果这本身并没有解决这个问题,那么您将能够在浏览页面时手动引发PropertyChanged
事件,这应该足以让WPF自己重绘并显示正确的选定项目。
设置IsSynchronizedWithCurrentItem="True"
为我工作!
您需要在SelectedItem属性之前放置ItemsSource属性。 前几天我遇到一个博客提到这个问题。
我有类似的问题,并确保我正确实施IEquatable解决了。 当绑定发生时,它试图看看对象是否匹配,所以确保你正确地实现你的相等性检查。
在这种情况下,selecteditem绑定不起作用,因为对象的哈希ID是不同的。
一个可能的解决scheme是
根据select的项目标识,恢复项目源集合上的对象,并将其设置为所选项目属性。
例:
<ctrls:ComboBoxControlBase SelectedItem="{Binding Path=SelectedProfile, Mode=TwoWay}" ItemsSource="{Binding Path=Profiles, Mode=OneWay}" IsEditable="False" DisplayMemberPath="Name" />
绑定到ItemSource的Property是:
public ObservableCollection<Profile> Profiles { get { return this.profiles; } private set { profiles = value; RaisePropertyChanged("Profiles"); } }
绑定到SelectedItem的属性是:
public Profile SelectedProfile { get { return selectedProfile; } set { if (this.SelectedUser != null) { this.SelectedUser.Profile = value; RaisePropertyChanged("SelectedProfile"); } } }
恢复代码是:
[Command("SelectionChanged")] public void SelectionChanged(User selectedUser) { if (selectedUser != null) { if (selectedUser is User) { if (selectedUser.Profile != null) { this.SelectedUser = selectedUser; this.selectedProfile = this.Profiles.Where(p => p.Id == this.SelectedUser.Profile.Id).FirstOrDefault(); MessageBroker.Instance.NotifyColleagues("ShowItemDetails"); } } } }
我希望它可以帮助你。 我花了很多时间寻找答案,但是我找不到。
当离开当前页面时,与ComboBox
的ItemsSource
属性关联的CollectionView
被清除。 而且由于ComboBox
IsSyncronizedWithCurrent
属性默认为true,所以SelectedItem
和SelectedValue
属性被重置。
这似乎是绑定中的内部数据types问题。 正如其他人上面所build议的那样,如果使用SelectedValue
而不是通过绑定视图模型上的int属性,它将起作用。 对于你来说快捷方式是重写MyObject上的Equals
运算符,以便在比较两个MyObjects时比较实际的Id
属性。
另一个提示:如果你重组你的视图模型并使用SelectedValue
,只有在SelectedValuePath=Id
其中Id
是int
时才使用它。 如果使用string键,则绑定到ComboBox
的Text
属性而不是SelectedValue
。
我之前也注意到了这种行为。 我注意到SelectedIndex属性不会导致相同的错误。 如果你可以重构你的ViewModel来显示选定的项目的索引,并绑定到那个,你应该很好去。
我有同样的问题。 事情是。 选定的项目不知道它应该从集合中使用哪个对象。 所以你必须说select的项目使用集合中的项目。
public MyObject SelectedObject { get { Objects.find(x => x.id == _selectedObject.id) return _selectedObject; } set { _selectedObject = value; } }
我希望这有帮助。
我有一个非常简单的回答这个问题。 首先将下面的代码添加到View IsSynchronizedWithCurrentItem =“True”。
接下来,当您在ViewModel中分配一个新的对象时,该对象将被保存到该属性而不是私有成员。
Viewmodel Proptery应该看起来像这样
public Role SelectedObject { get { return object; } set { if (value != null) { if (!object.Equals(value)) { object = value; OnPropertyChanged(() => SelectedObject ); } } } }
这应该解决这个问题。
我在这个问题上争取了一段时间。 在我的情况下,我使用复杂types(List)作为项目源,并使用KeyType作为选定的值。 在加载事件中,KeyType被设置为null。 这使一切都打破。 当密钥更改时,所有子元素都不会更新。 事实certificate,当我添加一个检查,以确保KeyType的build议值不为空,一切按预期工作。
#region Property: SelectedKey // s.Append(string.Format("SelectedKey : {0} " + Environment.NewLine, SelectedKey.ToString())); private KeyType _SelectedKey = new KeyType(); public KeyType SelectedKey { get { return _SelectedKey; } set { if(value != null ) if (!_SelectedKey.Equals(value)) { _SelectedKey = value; OnPropertyChanged("SelectedKey"); } } } #endregion SelectedKey
SelectedValuePath
和SelectedValue
的types必须完全相同。
例如,如果SelectedValuePath
的types是Int16
并且绑定到SelectedValue
的属性的types是int
则它将不起作用。
我花了好几个小时才find这个问题,这就是为什么我问了这么多问题之后,我在这里回答。 也许像我这样的另一个可怜的家伙有同样的问题可以看到它。
我遇到了一个显示颜色列表(List <Brush>)的ComboBox的问题。
select颜色是可能的,但是当selectclosures时不显示(尽pipe属性被改变了!)
此修复程序覆盖了 ComboBox(刷子)中所选types的Equals(object obj)方法 ,因为Brush是密封的,所以这很简单。 所以我写了一个EqualityBrush类,其中包含一个Brush并实现Equals:
public class EqualityBrush { public SolidColorBrush Brush { get; set; } public override bool Equals(object o) { if (o is EqualityBrush) { SolidColorBrush b = ((EqualityBrush)o).Brush; return b.Color.R == this.Brush.Color.R && b.Color.G == this.Brush.Color.G && b.Color.B == this.Brush.Color.B; } else return false; } }
使用我的新的EqualityBrush类而不是正常的刷类的列表修复了问题!
我的Combobox XAML看起来像这样:
<ComboBox ItemsSource="{Binding BuerkertBrushes}" SelectedItem="{Binding Brush, Mode=TwoWay}" Width="40"> <ComboBox.Resources> <DataTemplate DataType="{x:Type tree:EqualityBrush}"> <Rectangle Width="20" Height="12" Fill="{Binding Brush}"/> </DataTemplate> </ComboBox.Resources> </ComboBox>
请记住, ViewModel中的“Brush”属性现在必须是Type EqualityBrush!
这可能是你应用DataContext到页面的方式。 在WPF中,每当你导航到一个页面,一切都会被重新初始化,构造函数被调用,加载的方法,一切。 所以如果你在你的View中设置你的DataContext,你无疑会吹走用户select的SelectedItem。 为了避免使用您的网页的KeepAlive财产。
<Page KeepAlive="True" ...> ... </Page>
这将导致在返回到已经访问过的页面时,只会触发Loaded事件。 所以你需要确保你在初始化时设置DataContext(在外部或在构造函数中)而不是Load。
但是,这只适用于该页面的实例。 如果您导航到该页面的新实例,则会再次调用构造函数。
ComboBox.SelectionBoxItem.ToString()
IsSyncronizedWithCurrent = False将使其工作。
使用加载事件:
private void cmb_Loaded(object sender, RoutedEventArgs e) { if (cmb.Items.Count > 0) cmb.SelectedIndex = 0; }
这个对我有用。
我通过在UserControl_Loaded事件中添加调度程序来解决问题
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action(() => { combobox.SelectedIndex = 0; }));