1
votes

I am trying to implement a basic Master-Detail view, based on an Entity Framework 6 DbContext backed by a MySQL database. The table configuration is as simple as it may get:

ER Diagram showing one-to-many relationship between two simple tables

The form of my test application contains two ComboBox elements - one for the master category and one for a subcategory (In my case, master is the type of a electronic component, e.g. "IC" and detail is more specific, like "FPGA", "Microcontroller" etc.).

Two Comboboxes ("MainType" and "SubType"), with the lower one showing a class name instead of a list of items

The DataSource property of each ComboBox is set to their own BindingSource via the form designer.

The binding sources themselves have their DataSource properties set in different ways, adhering to various tutorials I found:

  • Master BindingSource: Set to the DbSet representing the comp_main_type table via a BindingList
  • Detail BindingSource: Set to the master binding source, with the DataMember property set to the "navigation property" from master to detail
ExampleEntities entities = new ExampleEntities();
entities.comp_main_type.Load();
entities.comp_sub_type.Load();

BindingSourceCompMainType.DataSource = entities.comp_main_type.Local.ToBindingList();

BindingSourceCompSubType.DataSource = BindingSourceCompMainType;
BindingSourceCompSubType.DataMember = "comp_sub_type";

In part, this works as expected - the master ComboBox is populated correctly, but the detail ComboBox is not. Instead of showing individual items, the type name of a HashSet is shown as the only item:

System.Collections.Generic.HashSet`1[ExampleApp.comp_sub_type]

The debugger shows that this HashSet indeed contains the correct items filtered by the selected master item:

Debugger showing the items of the ComboBox items list

I was unable to find the cause of this situation - why isn't the detail ComboBox populated with the items of the HashSet, but with the HashSet itself?

1
Take a look at Entity Framework Databinding with WinForms. This step-by-step walkthrough shows how to bind POCO types to Window Forms (WinForms) controls in a “master-detail" form. The application uses Entity Framework to populate objects with data from the database, track changes, and persist data to the database. - Reza Aghaei
Thank you, checked the guide a second time and made some changes as described in my answer, now it works! - Alexander Willer

1 Answers

1
votes

After checking the link Reza Aghaei provided, the cause of the issue became quite obvious: Somehow, I skipped an important section of the guide.

It's necessary to add the following class:

using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Data.Entity;

namespace WinFormswithEFSample
{
    public class ObservableListSource<T> : ObservableCollection<T>,     IListSource
            where T : class
    {
        private IBindingList _bindingList;

        bool IListSource.ContainsListCollection { get { return false; } }

        IList IListSource.GetList()
        {
            return _bindingList ?? (_bindingList = this.ToBindingList());
        }
    }
}

Afterwards, the code-generation template must be modified:

Find the ProductModel.tt file which will be nested under the ProductModel.edmx file

Double-click on the ProductModel.tt file to open it in the Visual Studio editor

Find and replace the two occurrences of “ICollection” with “ObservableListSource”. These are located at approximately lines 296 and 484.

Find and replace the first occurrence of “HashSet” with “ObservableListSource”. This occurrence is located at approximately line 50. Do not replace the second occurrence of HashSet found later in the code.

Save the ProductModel.tt file. This should cause the code for entities to be regenerated. If the code does not regenerate automatically, then right click on ProductModel.tt and choose “Run Custom Tool”.

Source: https://msdn.microsoft.com/en-us/library/jj682076(v=vs.113).aspx

After applying these changes, the detail view works as expected.