How can I bind an Entity Framework association to a ComboBox?
I'm working on an internal software-tracking program, and each program revision is assigned a lead programmer from the Employee database. My simple model looks like this so far:
Initially I had a RevisionBindingSource
object which was bound to my Revisions
collection:
Dim container as new EntityContainer
revisionBindingSource.DataSource = container.Revisions
...
dgRevisions.DataSource = revisionBindingSource
dgRevisions.DataMemeber = ""
This worked well, and I was able to bind to various properties I required, such as the application title:
lblAppTitle.DataBindings.Add("Text",revisionBindingSource,"Application.Title")
However, I now need a ComboBox whose items are bound to the list of employees, and whose selected value is bound to the lead programmer of the current revision. I tried making a new employeeBindingSource
, but realized that I have no binding member for Value
:
employeeBindingSource.DataSource = container.Employees
...
cboLead.DataSource = employeeBindingSource
cboLead.DisplayMember = "Name.Display" 'Name is a complex type'
cboLead.ValueMember = '??
So I rewrote some 开发者_C百科of my bindings to only have one bindingSource
:
bindingSource.DataSource = container
...
dgRevisions.DataSource = bindingSource
dgRevisions.DataMemeber = "Revisions"
...
cboLead.DataSource = bindingSource
cboLead.DisplayMember = "Employees.Name.Display"
cboLead.ValueMember = "Employees"
...
lblAppTitle.DataBindings.Add("Text",bindingSource,"Revisions.Application.Title")
This still doesn't even populate the ComboBox with anything.
Which pattern is better for me to use - two distinct binding sources, or one? What am I doing wrong in binding my ComboBox? And once my ComboBox populates, how can I bind the current value to the revision's lead programmer?
Sorry for the long-winded question, and thank you.
There is nothing wrong with having more than one binding source on your form. In fact, "chaining" binding sources like you are suggesting above can be a convenient strategy.
However, in this situation, there is a missing link that you will need to fill in to support binding the .Value
property to the actual EF object: you will need to create a separate class for binding purposes. This technique is also very useful when binding to enumerations.
This technique is very common when your EF data model doesn't quite match how you want your UI to work. For WPF (not WinForms as in this example), this is often referred to as part of a ViewModel. After you do this a few times, it will become second nature.
Here is a sample implementation of the class you will need to create:
public class EmployeeBindingObject
{
public Employee Employee { get; private set; }
public string EmployeeName
{
get { return this.Employee.Name; }
}
private EmployeeBindingObject(Employee employee)
{
this.Employee = employee;
}
/// <summary>
/// Gets a binding list for a specified list of Employees.
/// </summary>
/// <param name="types"></param>
/// <returns></returns>
public static IBindingList GetBindingList(IEnumerable<Employee> employees)
{
BindingList<EmployeeBindingObject> result = new BindingList<EmployeeBindingObject>();
foreach (var ee in employees)
{
result.Add(new EmployeeBindingObject(ee));
}
return result;
}
}
Once you create this class, you should compile and then create a Data Source (Data -> Add New Data Source...) for EmployeeBindingObject.
- Set the
ValueMember
toEmployee
- Set the
DisplayMember
toEmployeeName
- Set the
SelectedValue
property to your other BindingSource'sEmployee
property. Then, in your code, you need to initialize the binding object BindingSource as follows:
employeeBindingObjectBindingSource.DataSource = EmployeeBindingObject.GetBindingList(container.Employees)
精彩评论