Reputation: 535
I have two object: UserDto and RoleDto. User has a property which is the RoleDto. In my viewmodel I have the following:
public UserDto User
{
get { return _user; }
set
{
if (_user == value) return;
_user = value;
User.PropertyChanged += UserPropertyChanged;
OnPropertyChanged("User");
}
}
private UserDto _user;
public IEnumerable<RoleDto> Roles { get; set; } //I load all available roles in here
In the view, I want to select the role that the user belongs. This is how I define the combobox in the view:
<ComboBox Grid.Row="3" Grid.Column="1" Margin="5" ItemsSource="{Binding Roles}" SelectedItem="{Binding User.Role, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Description" />
If I try to create a new user and select a role from the combobox, it is correctly binded to the user. The problem is that when I load a user that already exists, the role is not displayed in the combobox (even the user has a role defined).
Any help please?
Thanks in advance
Upvotes: 3
Views: 11301
Reputation: 81
In my opinion the second option on this page is the easiest way.
https://rachel53461.wordpress.com/2011/08/20/comboboxs-selecteditem-not-displaying/
You can override the equals property on your object so that it returns true if the items have the same data. Then when the combo box box goes to check to make sure your item is in the selection it will find a match.
Upvotes: 4
Reputation: 1746
The other way to solve this problem is using Converter
on Binding
. when you use binding to bind SelectedItem
, WPF will check the reference of SelectedItem
against all objects inside ItemsSource
property and of course if there was no match, SelectedItem
will be empty. using Converter
you can tell WPF that how it should match SelectedItem
.
In this case you just need find SelectedItem
among ItemsSource
and return it to Binding
. so follow these steps:
1- Create a class and implement IValueConverter
. It has two methods: Convert
and ConvertBack
2- for Convert
method do something like this:
public class MySelecteItemBindingConverter : IValueConverter
{
public object Convert(object value, Type targetType,
object parameter, CultureInfo culture)
{
var mySelectedItem = value as MySelectedItemType;
var myItemsSource = parameter as List<MySelectedItemType>;
var matchedItem = myItemsSource.FirstOrDefault(i=>i.Id == mySelectedItem.Id);
return matchedItem;
}
public object ConvertBack(object value, Type targetType,
object parameter, CultureInfo culture)
{
// Do just like Convert method
}
}
3- Use this Converter
on your Binding
like this:
var myBinding = new Binding("YourBindingPath");
myBinding.Converter = new MySelectedItemBindingConverter();
myBinding.ConverterParameter = myItemsSource; //this is List<MySelectedItemType> in this example
myCombo.SetBinding(ComboBox.SelectedItemProperty, myBinding);
Note: if you want to do binding from XAML
you can not pass ConverterParameter
like this, instead you should create a static
list and use that as ItemsSource
or use MultiBinding
to pass your ConverterParameter
using a trick. here there is a good and simple explanation about it: Binding ConverterParameter
Upvotes: 0
Reputation: 18578
This is because the reference of RoleDTO
that your UserDTO
has, does not match any of the RoleDTOs
in Roles
collection which you set as ItemsSource
of ComboBox
.
Better define a property on your ViewModel like
public RoleDTO SelectedRole
{
get { return Roles.FirstOrDefault(role => role.Role == User.RoleDto.Role); }
set { User.RoleDto = value; OnPropertyChanged("SelectedRole"); }
}
and set it as SelectedItem of you combobox
ItemsSource="{Binding Roles}" SelectedItem="{Binding SelectedRole, Mode=TwoWay, ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="Description" />
Upvotes: 6