Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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:

Entity Framework model

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 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.

like image 783
dlras2 Avatar asked Aug 09 '11 19:08

dlras2


1 Answers

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.

  1. Set the ValueMember to Employee
  2. Set the DisplayMember to EmployeeName
  3. Set the SelectedValue property to your other BindingSource's Employee property.
  4. Then, in your code, you need to initialize the binding object BindingSource as follows:

     employeeBindingObjectBindingSource.DataSource = 
         EmployeeBindingObject.GetBindingList(container.Employees)
    
like image 109
Kevin McCormick Avatar answered Sep 27 '22 19:09

Kevin McCormick