Reputation: 709
I have an ObservableCollection<Employee>...
, an ObservableCollection<Departments>
and Enployee
is defined as
public class Employee
{
[Key]
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
public int DepId { get; set; }
[ForeignKey("DepId")]
public virtual Departments Departments { get; set; }
}
and Department
is defined as
public class Departments
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public virtual IEnumerable<Employee> Employees { get; set; }
}
In the database I have
It looks like last ComboBox fails to locate the DepId which belongs to the corresponding Employee!! Any ideas guys?
<DataGrid Name="DataGrid1" Grid.Row="3" Margin="10,0,10,10"
RenderOptions.ClearTypeHint="Enabled"
TextOptions.TextFormattingMode="Display"
CanUserAddRows="False"
CanUserDeleteRows="False"
SelectionUnit="FullRow"
AutoGenerateColumns="false"
SelectedItem="{Binding CurrentSelectedEmployee, Mode=TwoWay}"
ItemsSource="{Binding Employees, Mode=TwoWay}">
<DataGrid.Columns>
<!--Column 1: Employee Id-->
<DataGridTextColumn Header="Emplyee Id" Binding="{Binding Id}"/>
<!--Column 2: First Name-->
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/>
<!--Column 3: Last Name-->
<DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"/>
<!--Column 4: Birth Day-->
<DataGridTemplateColumn Header="Birth Day" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding Birthday}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!--Column 5: Department Id-->
<DataGridTemplateColumn Header="Department" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Departments}"
DisplayMemberPath="Name" SelectedValuePath="Id" SelectedValue="{Binding DepId}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
It looks like last ComboBox fails to locate the DepId which belongs to the corresponding Employee!! Any ideas guys?
UPDATE: My viewModel
public class MainViewModel : ViewModelBase
{
private readonly ManagerDbContext _context = new ManagerDbContext();
public MainViewModel()
{
}
private IEnumerable<Departments> _departments;
public ObservableCollection<Departments> Departments
{
get
{
return
new ObservableCollection<Departments>(_context.Departments);
}
set
{
_departments = value;
RaisePropertyChanged("Departments");
}
}
private IEnumerable<Employee> _employee;
public IEnumerable<Employee> Employees
{
get
{
return
new ObservableCollection<Employee>(_context.Employees.Include(e => e.Department));
}
set
{
_employee = value;
RaisePropertyChanged("Employees");
}
}
private Employee _currentSelectedEmployee;
public Employee CurrentSelectedEmployee
{
get
{
return _currentSelectedEmployee;
}
set
{
_currentSelectedEmployee = value;
RaisePropertyChanged("CurrentSelectedEmployee");
}
}
}
Upvotes: 0
Views: 2039
Reputation: 132558
The correct way to set a ComboBox's ItemsSource in a DataGrid would be something like this :
// simplified datacontext class
public class MainViewModel
{
public ObservableCollection<Employee> Employees;
public ObservableCollection<Department> Departments;
}
<DataGrid Name="DataGrid1" ItemsSource="{Binding Employees}">
<DataGrid.Columns>
<DataGridTextColumn Header="Emplyee Id" Binding="{Binding Id}"/>
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/>
<DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"/>
<DataGridTemplateColumn Header="Department" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<!-- Note the change in the ItemsSource Binding -->
<ComboBox ItemsSource="{Binding ElementName=DataGrid1, Path=DataContext.Departments}"
DisplayMemberPath="Name" SelectedValuePath="Id" SelectedValue="{Binding DepId}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
By using an ElementName (or RelativeSource) binding here, we only need to maintain one copy of the entire Departments
list in our main view model, instead of needing a separate copy of the entire Departments
list on each and every data item in the DataGrid.
But anyways, your actual problem appears to be that you're setting the ComboBox.ItemsSource
to Employee.Departments
, which is defined as
public virtual Departments Departments { get; set; }
Since this is not a collection or a list of objects, the ItemsSource does not bind correctly, and therefore the SelectedValue binding does not work as expected.
Upvotes: 0
Reputation: 166
now I see the problem. When you use the ItemsSource, then each item of ComboBox gets the binding to Department entity, not to Employee. Does Department entity has a property DepId? Probably not, and that's is the problem. If you need to refer to Employee you need to do this.
{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type DataGrid}}, Path=DepId}
Employee.Departments what is this? Are you sure it's initialized?
This is what works for me:
{
public partial class MainWindow : Window
{
public ObservableCollection<Employee> Employees { get; set; }
public MainWindow()
{
InitializeComponent();
Department dept1 = new Department() { Id = 1, Name = "aaa" };
Department dept2 = new Department() { Id = 2, Name = "bbb" };
Department dept3 = new Department() { Id = 3, Name = "ccc" };
ObservableCollection<Department> depts = new ObservableCollection<Department>();
depts.Add(dept1);
depts.Add(dept2);
depts.Add(dept3);
this.Employees = new ObservableCollection<Employee>();
this.Employees.Add(new Employee() { Id = 1, Birthday = DateTime.Now, FirstName = "aaa", LastName = " aaaa", DepId = 1, Departments = depts });
this.Employees.Add(new Employee() { Id = 2, Birthday = DateTime.Now, FirstName = "aaa", LastName = " bbbb", DepId = 2, Departments = depts });
this.Employees.Add(new Employee() { Id = 3, Birthday = DateTime.Now, FirstName = "aaa", LastName = " cccc", DepId = 3, Departments = depts });
this.Employees.Add(new Employee() { Id = 4, Birthday = DateTime.Now, FirstName = "aaa", LastName = " dddd", DepId = 2, Departments = depts });
this.DataContext = this;
}
}
}
public class Employee
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime Birthday { get; set; }
public int DepId { get; set; }
public virtual ObservableCollection<Department> Departments { get; set; }
}
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
}
and this is XAML:
<DataGrid Name="DataGrid1" Grid.Row="3" Margin="10,0,10,10"
RenderOptions.ClearTypeHint="Enabled"
TextOptions.TextFormattingMode="Display"
CanUserAddRows="False"
CanUserDeleteRows="False"
SelectionUnit="FullRow"
AutoGenerateColumns="false"
SelectedItem="{Binding CurrentSelectedEmployee, Mode=TwoWay}"
ItemsSource="{Binding Employees, Mode=TwoWay}">
<DataGrid.Columns>
<!--Column 1: Employee Id-->
<DataGridTextColumn Header="Emplyee Id" Binding="{Binding Id}"/>
<!--Column 2: First Name-->
<DataGridTextColumn Header="First Name" Binding="{Binding FirstName}"/>
<!--Column 3: Last Name-->
<DataGridTextColumn Header="Last Name" Binding="{Binding LastName}"/>
<!--Column 4: Birth Day-->
<DataGridTemplateColumn Header="Birth Day" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<DatePicker SelectedDate="{Binding Birthday}" BorderThickness="0" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<!--Column 5: Department Id-->
<DataGridTemplateColumn Header="Department" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Departments}"
DisplayMemberPath="Name" SelectedValuePath="Id" SelectedValue="{Binding DepId}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
</DataGrid.Columns>
</DataGrid>
Upvotes: 1
Reputation: 1256
Please have look, it works like that:
<!--Column 5: Department Id-->
<DataGridTemplateColumn Header="Department" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<ComboBox ItemsSource="{Binding Departments}"
DisplayMemberPath="Name" SelectedIndex="0" SelectedValuePath="Id" SelectedValue="{Binding DepId}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
and code behind:
public partial class MainWindow : Window
{
private ObservableCollection<Employee> employees;
public ObservableCollection<Employee> Employees
{
get { return employees; }
set { employees = value; }
}
public MainWindow()
{
InitializeComponent();
this.DataContext= this;
Department dept1 = new Department() { Id = 1, Name = "aaa" };
Department dept2 = new Department() { Id = 2, Name = "bbb" };
Department dept3 = new Department() { Id = 3, Name = "ccc" };
ObservableCollection<Department> depts = new ObservableCollection<Department>();
depts.Add(dept1);
depts.Add(dept2);
depts.Add(dept3);
Employees =new ObservableCollection<Employee>();
this.Employees.Add(new Employee() { Id = 1, Birthday = DateTime.Now, FirstName = "aaa", LastName = " aaaa", DepId = 1, Departments = depts });
this.Employees.Add(new Employee() { Id = 2, Birthday = DateTime.Now, FirstName = "aaa", LastName = " bbbb", DepId = 2, Departments = depts });
this.Employees.Add(new Employee() { Id = 3, Birthday = DateTime.Now, FirstName = "aaa", LastName = " cccc", DepId = 3, Departments = depts });
this.Employees.Add(new Employee() { Id = 4, Birthday = DateTime.Now, FirstName = "aaa", LastName = " dddd", DepId = 2, Departments = depts });
}
}
Upvotes: 0