Reputation: 35
I am using mvvm in wpf. I am setting a form to update user data. I have a combobox to select gender of user. i have added combobox items manually in source. when loading data to form all fields other fields are displaying correctly. but combobox is not displaying anything. I have used twoWay binding and the values i am selecting from form are getting in the viewModel.I have been searching for hours and found many similar problem, but nothing worked for me. I am inserting my code segment bellow. Please give me a solution.
<ComboBox
Grid.Column="2"
SelectedItem="{Binding SelectedEmployees.gender, Mode=TwoWay}"
SelectedValue="{Binding SelectedEmployees.gender, Mode=TwoWay}"
>
<ComboBoxItem Content="Male"/>
<ComboBoxItem Content="Female"/>
</ComboBox>
my viewModel code is as bellow
class EmployeesModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private iServiceClient serviceClient = new iServiceClient();
public EmployeesModel()
{
this.RefreshEmployees();
}
private void RefreshEmployees()
{
this.serviceClient.GetAllEmployeesCompleted += (s, e) =>
{
this.employees = e.Result;
};
this.serviceClient.GetAllEmployeesAsync();
}
private IEnumerable<Employee> employees;
public IEnumerable<Employee> Employees
{
get
{
return this.employees;
}
set
{
this.employees = value;
this.OnPropertyChanged("Employees");
}
}
private Employee selectedEmployees;
public Employee SelectedEmployees
{
get
{
return this.selectedEmployees;
}
set
{
this.selectedEmployees = value;
this.OnPropertyChanged("SelectedEmployees");
}
}
public void OnPropertyChanged(string PropertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(PropertyName));
}
}
}
and SelectedEmployees class is
public class Employee
{
[Key]
public int id { get; set; }
public DateTime JoiningDate { get; set; }
public string name { get; set; }
public string gender { get; set; }
public string mobile { get; set; }
public string post { get; set; }
public string salaryType { get; set; }
public decimal salary { get; set; }
public string docname { get; set; }
public int validit { get; set; }
}
Upvotes: 1
Views: 3171
Reputation: 37059
This is probably the best approach, particularly if you mean to learn MVVM: Use an enum type for Gender. "LOL" is never a valid gender so don't let anybody try to use it. Populate the ComboBox by binding it to a static collection. Initialize SelectedEmployees.gender
to the value you want to be the default and the binding will take care of the rest.
<ComboBox
SelectedItem="{Binding SelectedEmployees.gender}"
ItemsSource="{Binding SelectedEmployees.Genders}"
/>
C#
public class SelectedEmployeesViewModel : ViewModelBase
{
/* ...other stuff... */
private Gender _gender = Gender.Male;
public Gender gender
{
get { return _gender; }
set
{
if (value != _gender)
{
_gender = value;
OnPropertyChanged();
}
}
}
}
public enum Gender
{
Male, Female
}
public static class EnumValues
{
public static IEnumerable<Gender> Genders => Enum.GetValues(typeof(Gender)).Cast<Gender>();
}
There are other approaches. I advise against going with a string, but this is illustrative at least:
private String _gender = "Male";
public String gender
{
get { return _gender; }
set
{
if (value != _gender)
{
_gender = value;
OnPropertyChanged();
}
}
}
Does your SelectedEmployees
class implement INotifyPropertyChanged
, and does SelectedEmployees.gender
raise PropertyChanged
when its value changes?
Get rid of Mode=TwoWay
on the binding; you don't need to do that explicitly. It's the default for any binding you put on ComboBox.SelectedValue
or on ComboBox.SelectedItem
.
As Andy pointed out in comments, your SelectedValue and SelectedItem are both going to be instances of ComboBoxItem
, because that's how you populated your ComboBox. The string you want is in the Content property of the ComboBoxItems, so use SelectedValuePath
to tell the ComboBox about that, and bind to the SelectedValue
property. SelectedItem
will be the ComboBoxItem
itself, which is useless to you.
<ComboBox
SelectedValue="{Binding SelectedEmployees.gender}"
SelectedValuePath="Content"
>
<ComboBoxItem Content="Male" />
<ComboBoxItem Content="Female" />
</ComboBox>
Here's another approach: Populate the ComboBox with strings.
<ComboBox
SelectedItem="{Binding SelectedEmployees.gender}"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
>
<sys:String>Male</sys:String>
<sys:String>Female</sys:String>
</ComboBox>
See Andy's answer for yet another way to populate the ComboBox with strings via ItemsSource
.
Upvotes: 1
Reputation: 12276
I suspect that SelectedEmployees.gender is not type comboboxitem.
Taking the shortcut of creating comboboxitems directly in the combobox is a bad move.
When I do:
xmlns:sys="clr-namespace:System;assembly=mscorlib">
<Window.DataContext>
<local:MainWIndowViewModel/>
</Window.DataContext>
<Window.Resources>
<x:Array Type="sys:String" x:Key="Genders">
<sys:String>Male</sys:String>
<sys:String>Female</sys:String>
</x:Array>
</Window.Resources>
<Grid>
<ComboBox
SelectedItem="{Binding gender, Mode=TwoWay}"
ItemsSource="{StaticResource Genders}"
/>
</Grid>
I get a string instead of a comboboxitem in my bound gender. You probably want something rather more like that.
Upvotes: 3