none
populate combobox from List<> RRS feed

  • Question

  • Hi All.

    I created classes to populate two dependent combobox

            public static List<Employee> GetEmployees(string department)
            {
                return new List<Employee>();
            }

            public static List<string> GetDepartment()
            {
                using (DeptModel context = new DeptModel())
                {
                    List<string> departments = context.DeptEmployees.Select(d => d.Department).Distinct().ToList();
                    return applications;
                }
            }

            public void PopulateDeptCombo()
            {
                List<string> departments = GetDepartment();
                cbDept.ItemsSource = departments;
            }

    How populate and filter EmpCombo depended selection in DeptCombo? Both used same entity table.

    Thanks.

    Friday, March 20, 2020 1:30 AM

All replies

  • Hello,

    This is done with Entity Framework Core, works with Entity Framework 6 also.

    The following, select a category in the first ComboBox displays products for that category.

    In the category model, the following was added which serves as DisplayMember for the category ComboBox. 

    public override string ToString() => CategoryName;

    Similarly in the Product model.

    public override string ToString() => ProductName;

    The Form  has two BindingList for the second ComboBox, one with all products, one with filtered products done first in form shown then on the category ComboBox SelectedIndexChanged event.

    using System;
    using System.ComponentModel;
    using System.Linq;
    using System.Windows.Forms;
    using Microsoft.EntityFrameworkCore;
    using NorthWindEntityCore.Contexts;
    using NorthWindEntityCore.Models;
    
    namespace CoreDualComboBoxes
    {
        public partial class Form1 : Form
        {
            private readonly NorthContext _context = new NorthContext();
            private BindingList<Product> _bindingList = new BindingList<Product>();
            private BindingList<Product> _bindingListFilter = new BindingList<Product>();
            public Form1()
            {
                InitializeComponent();
                Shown += Form1_Shown;
                CategoryComboBox.SelectedIndexChanged += CategoryComboBox_SelectedIndexChanged;
            }
    
            private void CategoryComboBox_SelectedIndexChanged(object sender, EventArgs e)
            {
    
                int categoryIdentifier = ((Category)CategoryComboBox.SelectedItem).CategoryId;
                _bindingListFilter = new BindingList<Product>(
                    _bindingList.Where(p => p.CategoryId == categoryIdentifier).ToList());
    
                ProductComboBox.DataSource = _bindingListFilter;
            }
    
            private void Form1_Shown(object sender, EventArgs e)
            {
    
                var categories = _context.Categories.AsNoTracking()
                    .OrderBy(cat => cat.CategoryName).ToList();
    
                CategoryComboBox.DataSource = categories;
    
                _bindingList = new BindingList<Product>(_context.Products.AsNoTracking()
                    .OrderBy(prod => prod.ProductName).ToList());
    
                _bindingListFilter = new BindingList<Product>(
                    _bindingList.Where(p => p.CategoryId == categories.FirstOrDefault().CategoryId).ToList());
    
                ProductComboBox.DataSource = _bindingListFilter;
    
            }
        }
    }
    


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Friday, March 20, 2020 3:31 AM
    Moderator
  • Hi Karen Payne, Thanks for reply.

    That is very interesting sample. But can you show me how to populate EmpCombo by the way like I posted? I just start learn C#. I tried like

            public void PopulateEmpCombo()
            {
                using (DeptModel context = new DeptModel())
                {
                    List<string> emps = context.DeptEmployees.Where(a => a.Departmnt == cbDept.SelectedItem.ToString()).Select(r => r.Employee).ToList();
                }
                cbEmp.ItemsSource = emps;
            }

    But it not work.   

    I will very appreciate help. Thanks

    Friday, March 20, 2020 4:12 AM
  • Hi zleug,

    Thank you for posting here.

    I guess this is a wpf project, isn't it?

    Did you forget to add events to the first Combobox?

    You can double click on the first ComboBox, it will generate a "SelectionChanged" event.

    Then, please refer to the following code.

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                List<Employee> allEmployees = GetData();
                List<int> departments = allEmployees.Select(d => d.Department_ID).Distinct().ToList();
    
                comboBox.ItemsSource =departments ;
                comboBox.SelectedIndex = 0;
    
            }
            private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
               int department_ID = int.Parse(comboBox.SelectedItem.ToString());
                List<Employee> allEmployees = GetData();
    
                //Both of the following ways work fine.
    
                //List<Employee> emps = allEmployees.Where(emp => emp.Department_ID == department_ID).ToList(); ;
                //comboBox1.ItemsSource = emps;
                //comboBox1.DisplayMemberPath = "Emp_Name";
                //comboBox1.SelectedIndex = 0;
    
                List<string> empsss = allEmployees.Where(a => a.Department_ID == department_ID).Select(r => r.Emp_Name).ToList();
                comboBox1.ItemsSource = empsss;
                comboBox1.SelectedIndex = 0;
            }
    
            private List<Employee> GetData() 
            {
                List<Employee> employees = new List<Employee>();
                employees.Add(new Employee() { Department_ID=1,Emp_ID=1,Emp_Name= "D1_A" });
                employees.Add(new Employee() { Department_ID=1,Emp_ID=2,Emp_Name= "D1_B" });
                employees.Add(new Employee() { Department_ID=1,Emp_ID=3,Emp_Name= "D1_C" });
                employees.Add(new Employee() { Department_ID=2,Emp_ID=4,Emp_Name= "D2_A" });
                employees.Add(new Employee() { Department_ID=2,Emp_ID=5,Emp_Name= "D2_B" });
                return employees;
            }
        }
        class Employee
        {
            public int Department_ID { get; set; }
            public int Emp_ID { get; set; }
            public string Emp_Name { get; set; }
        }
    

    Hope this could be helpful.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Friday, March 20, 2020 6:19 AM
  • Hi zleug,

    Thank you for posting here.

    I guess this is a wpf project, isn't it?

    Did you forget to add events to the first Combobox?

    You can double click on the first ComboBox, it will generate a "SelectionChanged" event.

    Then, please refer to the following code.

    public partial class MainWindow : Window
        {
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                List<Employee> allEmployees = GetData();
                List<int> departments = allEmployees.Select(d => d.Department_ID).Distinct().ToList();
    
                comboBox.ItemsSource =departments ;
                comboBox.SelectedIndex = 0;
    
            }
            private void comboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
            {
               int department_ID = int.Parse(comboBox.SelectedItem.ToString());
                List<Employee> allEmployees = GetData();
    
                //Both of the following ways work fine.
    
                //List<Employee> emps = allEmployees.Where(emp => emp.Department_ID == department_ID).ToList(); ;
                //comboBox1.ItemsSource = emps;
                //comboBox1.DisplayMemberPath = "Emp_Name";
                //comboBox1.SelectedIndex = 0;
    
                List<string> empsss = allEmployees.Where(a => a.Department_ID == department_ID).Select(r => r.Emp_Name).ToList();
                comboBox1.ItemsSource = empsss;
                comboBox1.SelectedIndex = 0;
            }
    
            private List<Employee> GetData() 
            {
                List<Employee> employees = new List<Employee>();
                employees.Add(new Employee() { Department_ID=1,Emp_ID=1,Emp_Name= "D1_A" });
                employees.Add(new Employee() { Department_ID=1,Emp_ID=2,Emp_Name= "D1_B" });
                employees.Add(new Employee() { Department_ID=1,Emp_ID=3,Emp_Name= "D1_C" });
                employees.Add(new Employee() { Department_ID=2,Emp_ID=4,Emp_Name= "D2_A" });
                employees.Add(new Employee() { Department_ID=2,Emp_ID=5,Emp_Name= "D2_B" });
                return employees;
            }
        }
        class Employee
        {
            public int Department_ID { get; set; }
            public int Emp_ID { get; set; }
            public string Emp_Name { get; set; }
        }

    Hope this could be helpful.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    There are several bad practices here.

    • Where you load mocked data mean in real life you are reading the database table each time the selected index changes. In my example data is only read once and then filtered on each selected index change.
    • There is no reason to set DisplayMember, this is what overriding ToString does as in my example. 
    • Why are you parsing the departement identifier when the type is known.
    • Last, none of your code is Entity Framework.

    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Friday, March 20, 2020 10:50 AM
    Moderator
  • Hi Karen Payne, Thanks for reply.

    That is very interesting sample. But can you show me how to populate EmpCombo by the way like I posted? I just start learn C#. I tried like

            public void PopulateEmpCombo()
            {
                using (DeptModel context = new DeptModel())
                {
                    List<string> emps = context.DeptEmployees.Where(a => a.Departmnt == cbDept.SelectedItem.ToString()).Select(r => r.Employee).ToList();
                }
                cbEmp.ItemsSource = emps;
            }

    But it not work.   

    I will very appreciate help. Thanks

    Hello,

    What you call interesting is the right path to take, what you have is incorrect and will not work. I like to give quality code samples, nothing that is not needed, keep things simple were simple is a relative term to how much experience a developer has, if not simple to them I recommend studying the code rather than discounting it for what seems not simple to that as it will over time. Does that make sense?

    Benefits to the code I posted.

    • Data is loaded once rather than many times as  Timon's example loads data each time the selected index changes. The two BindingList are needed to properly filter data which is something learned by working with Entity Framework a while.
    • Not the use of AsNoTracking. without this the DbContext is using more memory then actually needed.

    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange

    Friday, March 20, 2020 10:58 AM
    Moderator
  • There are several bad practices here.

    • Where you load mocked data mean in real life you are reading the database table each time the selected index changes. In my example data is only read once and then filtered on each selected index change.
    • There is no reason to set DisplayMember, this is what overriding ToString does as in my example. 
    • Why are you parsing the departement identifier when the type is known.
    • Last, none of your code is Entity Framework.


    Hi Karen,

    I want to explain what I did.

    For the first point, it was indeed my fault. This is not good. I will pay attention to it later.

    Second, sorry I didn't read your code in detail, so I didn't notice the ToString() method you rewritten.

    But I personally don't like to override ToString() method like this, because when the user selects an option in the second combobox, what if he wants to use other properties of this object? This means that the user must retrieve the data again based on the name obtained.

    Third, although Department_ID is known to be int, when it is obtained from combobox, the result will always be of type object.

    Last, using EF is certainly a better choice, but op mentioned that he is a beginner in C#, so before he learns to use EF, I think that the code involving EF will confuse his thinking. This often bothers me during my studies.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Monday, March 23, 2020 3:28 AM
  • Hello Timon,

    In regards to overriding .ToString, if you study my code in form Shown event the data is read in once while in SelectedIndexChanged data is read from the BindingList which was loaded once in form Shown so in this case data is only read once from the database.

    When properties are needed the following code reads cached data, not data from the database so using .ToString has no bearing on obtaining properties.

    var currentCategory = ((Category) CategoryComboBox.SelectedItem);
    var currentProduct = (Product)ProductComboBox.SelectedItem;

    Sure SelectedItem is a Object until cast as per above. I would like to see how you would handle this with reading from a database rather than mocked data as my example used a database.

    Regarding EF and the user being a beginner, I gave a solution with EF as they seem to be using EF from

    using (DeptModel context = new DeptModel())

    As context is a common name for a DbContext, I would find fault with the class name as a DbContext is not a model. So this is why I did my solution as EF, not LINQ to SQL.

    EDIT

    zleug actually did indicate EF in the following thread.


    Please remember to mark the replies as answers if they help and unmarked them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.

    NuGet BaseConnectionLibrary for database connections.

    StackOverFlow
    profile for Karen Payne on Stack Exchange


    Monday, March 23, 2020 10:56 AM
    Moderator
  • Hi Karen,

    Well, you are right, I am too careless, I should read each person's code carefully.

    Thank you for pointing out my mistake.

    Best Regards,

    Timon


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    Tuesday, March 24, 2020 1:17 AM