WPF MVVM ComboBox SelectedItem 或 SelectedValue 不起作用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/663881/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF MVVM ComboBox SelectedItem or SelectedValue not working
提问by cjibo
Update
更新
After a bit of investigating. What seems to be the issue is that the SelectedValue/SelectedItem is occurring before the Item source is finished loading. If I sit in a break point and wait a few seconds it works as expected. Don't know how I'm going to get around this one.
经过一番调查。问题似乎是 SelectedValue/SelectedItem 在 Item 源完成加载之前发生。如果我坐在断点处等待几秒钟,它会按预期工作。不知道我将如何解决这个问题。
End Update
结束更新
I have an application using in WPF using MVVM with a ComboBox. Below is the ViewModel Example. The issue I'm having is when we leave our page and migrate back the ComboBox is not selecting the current Value that is selected.
我有一个在 WPF 中使用 MVVM 和 ComboBox 的应用程序。下面是 ViewModel 示例。我遇到的问题是,当我们离开页面并迁移回 ComboBox 时,没有选择当前选择的值。
View Model
查看模型
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;
}
}
}
For the sake of this example lets say MyObject has two properties (Text and Id). My XAML for the ComboBox looks like this.
为了这个例子,假设 MyObject 有两个属性(Text 和 Id)。我的 ComboBox 的 XAML 看起来像这样。
XAML
XAML
<ComboBox Name="MyComboBox" Height="23" Width="auto"
SelectedItem="{Binding Path=SelectedObject,Mode=TwoWay}"
ItemsSource="{Binding Objects}"
DisplayMemberPath="Text"
SelectedValuePath="Id">
No matter which way I configure this when I come back to the page and the object is reassembled the ComboBox will not select the value. The object is returning the correct object via the get in the property though.
当我返回页面并重新组合对象时,无论我以哪种方式配置它,ComboBox 都不会选择该值。不过,该对象正在通过属性中的 get 返回正确的对象。
I'm not sure if this is just an issue with the way the ComboBox and MVVM pattern works. The text box binding we are doing works correctly.
我不确定这是否只是 ComboBox 和 MVVM 模式工作方式的问题。我们正在做的文本框绑定工作正常。
采纳答案by Orion Edwards
Have you tried implementing INotifyPropertyChanged
in your viewmodel, and then raise the PropertyChanged
event when the SelectedItem
gets set?
您是否尝试过INotifyPropertyChanged
在您的视图模型中实现,然后在设置PropertyChanged
时引发事件SelectedItem
?
If this in itself doesn't fix it, then you will be able to manually raise the PropertyChanged
event yourself when navigating back to the page, and that should be enough to get WPF to redraw itself and show the correct selected item.
如果这本身不能解决它,那么您将能够PropertyChanged
在导航回页面时自己手动引发事件,这应该足以让 WPF 重绘自身并显示正确的选定项目。
回答by rp7799
Setting IsSynchronizedWithCurrentItem="True"
worked for me!
设置IsSynchronizedWithCurrentItem="True"
对我有用!
回答by GuestPerson
You need to put the ItemsSource property BEFORE the SelectedItem property. I came across a blog a few days ago mentioning the issue.
您需要将 ItemsSource 属性放在 SelectedItem 属性之前。几天前我看到一个博客提到了这个问题。
回答by GuestPerson
I have had similar issues and it was solved by making sure I was implementing IEquatableproperly. When the binding occurs, it is trying to see if the objects match so make sure you are properly implementing your equality checking.
我遇到了类似的问题,通过确保我正确实施IEquatable解决了这个问题。当绑定发生时,它会尝试查看对象是否匹配,因此请确保您正确实施了相等性检查。
回答by Breno P. Lucena
In this case, the selecteditem bind doesn't work, because the hash id of the objects are different.
在这种情况下,selecteditem 绑定不起作用,因为对象的哈希 id 不同。
One possible solution is:
一种可能的解决方案是:
Based on the selected item id, recover the object on the itemsource collection and set the selected item property to with it.
根据选中的item id,恢复itemsource集合上的对象,并将选中的item属性设置为with。
Example:
例子:
<ctrls:ComboBoxControlBase SelectedItem="{Binding Path=SelectedProfile, Mode=TwoWay}" ItemsSource="{Binding Path=Profiles, Mode=OneWay}" IsEditable="False" DisplayMemberPath="Name" />
The Property binded to ItemSource is:
绑定到 ItemSource 的属性是:
public ObservableCollection<Profile> Profiles
{
get { return this.profiles; }
private set { profiles = value; RaisePropertyChanged("Profiles"); }
}
The property binded to SelectedItem is:
绑定到 SelectedItem 的属性是:
public Profile SelectedProfile
{
get { return selectedProfile; }
set
{
if (this.SelectedUser != null)
{
this.SelectedUser.Profile = value;
RaisePropertyChanged("SelectedProfile");
}
}
}
The recovery code is:
恢复代码为:
[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");
}
}
}
}
I hope it helps you. I spent a lot of my time searching for answers, but I couldn′t find.
我希望它能帮助你。我花了很多时间寻找答案,但我找不到。
回答by Dave
When leaving the current page, the CollectionView
associated with the ItemsSource
property of the ComboBox
is purged. And because the ComboBox
IsSyncronizedWithCurrent
property is true by default, the SelectedItem
and SelectedValue
properties are reset.
This seems to be an internal data type issue in the binding. As others suggested above, if you use SelectedValue
instead by binding to an int property on the viewmodel, it will work.
A shortcut for you would be to override the Equals
operator on MyObject so that when comparing two MyObjects, the actual Id
properties are compared.
当离开当前页面时,CollectionView
与 的ItemsSource
属性相关联的ComboBox
被清除。并且因为该ComboBox
IsSyncronizedWithCurrent
属性默认为 true,所以SelectedItem
和SelectedValue
属性会被重置。
这似乎是绑定中的内部数据类型问题。正如上面其他人所建议的,如果您SelectedValue
通过绑定到视图模型上的 int 属性来代替使用,它将起作用。一种快捷方式是覆盖Equals
MyObject 上的运算符,以便在比较两个 MyObject 时比较实际Id
属性。
Another hint: If you do restructure your viewmodels and use SelectedValue
, use it only when SelectedValuePath=Id
where Id
is int
. If using a string key, bind to the Text
property of the ComboBox
instead of SelectedValue
.
另一个提示:如果您确实重组了您的视图模型并使用了SelectedValue
,请仅在SelectedValuePath=Id
where Id
is时使用它int
。如果使用字符串键,则绑定到 的Text
属性ComboBox
而不是SelectedValue
。
回答by Abe Heidebrecht
I have noticed this behavior before as well. I have noticed that the SelectedIndex property doesn't cause the same bug. If you can restructure your ViewModel to expose the index of the selected item, and bind to that, you should be good to go.
我以前也注意到这种行为。我注意到 SelectedIndex 属性不会导致相同的错误。如果您可以重构您的 ViewModel 以公开所选项目的索引并绑定到该索引,那么您应该很高兴。
回答by StefanHa
I had the same problem. The thing is. The selected item doesnt know which object it should use from the collection. So you have to say to the selected item to use the item from the collection.
我有同样的问题。事情是。所选项目不知道它应该使用集合中的哪个对象。因此,您必须对所选项目说才能使用集合中的项目。
public MyObject SelectedObject
{
get
{
Objects.find(x => x.id == _selectedObject.id)
return _selectedObject;
}
set
{
_selectedObject = value;
}
}
I hope this helps.
我希望这有帮助。
回答by Tim
I have a very simply answer for this problem. First add the following code to the View IsSynchronizedWithCurrentItem="True".
对于这个问题,我有一个非常简单的答案。首先将以下代码添加到 View IsSynchronizedWithCurrentItem="True"。
Next when ever you assign a new object in the ViewModel to that Property SelectedObject should be saved to that Property and not the private member.
接下来,当您将 ViewModel 中的新对象分配给该属性时,应将 SelectedObject 保存到该属性而不是私有成员。
The viewmodel Proptery should look like this
视图模型属性应该是这样的
public Role SelectedObject
{
get { return object; }
set
{
if (value != null)
{
if (!object.Equals(value))
{
object = value;
OnPropertyChanged(() => SelectedObject );
}
}
}
}
This should fix the issue.
这应该可以解决问题。
回答by JCH2k
I had this problem with a ComboBox displaying a list of colors ( List<Brush> ).
Selecting a color was possible but it wasnt displayed when the selection closed (although the property was changed!)
我在显示颜色列表( List<Brush> )的 ComboBox 中遇到了这个问题。
可以选择颜色,但在选择关闭时没有显示(尽管属性已更改!)
The fix was overwriting the Equals(object obj) methodfor the type selected in the ComboBox (Brush), which wasnt simple because Brush is sealed. So i wrote a class EqualityBrushcontaining a Brush and implementing Equals:
修复是覆盖ComboBox (Brush) 中选择的类型的 Equals(object obj) 方法,这并不简单,因为 Brush 是密封的。所以我写了一个包含 Brush 并实现 Equals的类EqualityBrush:
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;
}
}
Using a List of my new EqualityBrush class instead of normal Brush class fixed the problem!
使用我的新 EqualityBrush 类的列表而不是普通的 Brush 类解决了这个问题!
My Combobox XAMLlooks like this:
我的组合框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>
Remember that my "Brush"-Property in the ViewModelnow has to be of Type EqualityBrush!
请记住,我在ViewModel中的“画笔”属性现在必须是 EqualityBrush 类型!