简体   繁体   中英

Populating datagridview winforms .net 4.0

I am having problems in loading a datagridview with 2 columns. Form with a Datagridview and 1 button.

Department (text) EmployeesByDpt( Combo)

I have a form with a datagridview and a Button (Load),when I press load the datagridview should be populated. clicking on the Employee Combo should display all the employees that belong to a particular department.

I cannot seem to get it to work ,below is what I have done,

Any suggestions?At the moment nothing shows. Thanks

Code (for semplicity I have put all together)

     public partial class Form2 : Form
{
    Repository repository;
    readonly DataGridViewTextBoxColumn colDepartment=new DataGridViewTextBoxColumn();
    readonly DataGridViewComboBoxColumn colComboEmployeesByDpt = new DataGridViewComboBoxColumn();
    public Form2()
    {
        InitializeComponent();
        repository = new Repository();
        SetupDataGridView();
    }

    private void SetupDataGridView()
    {
        dataGridView1.EditingControlShowing += OnEditingControlShowing;
        dataGridView1.CellValueChanged += OnCellsValueChanged;
        dataGridView1.AutoGenerateColumns = false;

        colDepartment.DataPropertyName = "Name";
        colDepartment.HeaderText = "Department Name";

        colComboEmployeesByDpt.DataPropertyName = "Employees";
        colComboEmployeesByDpt.HeaderText = "Employees";
        colComboEmployeesByDpt.DisplayMember = "FullName";
        //colComboEmployeesByDpt.DataSource = "FullName";


        dataGridView1.Columns.AddRange(new DataGridViewColumn[] { colDepartment ,colComboEmployeesByDpt});
    }

    private void OnCellsValueChanged(object sender, DataGridViewCellEventArgs e)
    {

    }

    private void OnEditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
    {
        if (dataGridView1.CurrentCell.ColumnIndex == colDepartment.Index)
        {
            var control = e.Control as DataGridViewComboBoxEditingControl;
            if (control != null)
            {
                var bs = control.DataSource as BindingSource;
                if (bs != null)
                {
                    var comboBox = e.Control as ComboBox;
                    BindingList<Employee> employees = repository.GetEmployeeByDepartments(control.Text);
                    comboBox.DataSource = employees;
                    object employeeValue = dataGridView1.Rows[dataGridView1.CurrentCell.RowIndex].Cells[colComboEmployeesByDpt.Index].Value;
                    if (employeeValue == DBNull.Value || employeeValue == null)

                    if (dataGridView1.CurrentCell.Value != DBNull.Value && dataGridView1.CurrentCell.Value != null)
                    {
                        control.SelectedValue = dataGridView1.CurrentCell.Value;
                    }
                }
            }
        }
    }

    private void btnLoad_Click(object sender, EventArgs e)
    {

        BindingList<Department> departments = repository.GetDepartments();

        dataGridView1.DataSource = departments;
        dataGridView1.Refresh();

    }
}

public class Department
{
    public Department()
    {
        Employees=new BindingList<Employee>();
    }
    public string Name { get; set; }
    public BindingList<Employee> Employees { get; set; }
}

public class Employee
{
    public string FullName { get; set; }
}

public class Repository
{
    public BindingList<Department> GetDepartments()
    {
        var departments=new BindingList<Department>();
        departments.Add(new Department{Name = "Food"});
        departments.Add(new Department{Name = "Travel"});
        departments.Add(new Department{Name = "Beauty"});
        return departments;
    }
    public BindingList<Employee> GetEmployeeByDepartments(string name)
    {
        var employees = new BindingList<Employee>();
        switch (name)
        {
            case "Food":
                employees.Add(new Employee { FullName = "Jim Bloggs1" });
                employees.Add(new Employee { FullName = "Jim Bloggs2" });
                break;
            case "Travel":
                employees.Add(new Employee { FullName = "Marc Smith1" });
                employees.Add(new Employee { FullName = "Marc Smith2" });
                break;
            case "Beauty":
                  employees.Add(new Employee { FullName = "Mario XXX1" });
                  employees.Add(new Employee { FullName = "Mario XXX2" });
                break;

        }

        return employees;
    }
}

Running your exact code, I ran into several problems. The following explanation will show you what I did to fix each subsequent problem but with a warning: In the end I couldn't make a selection from the ComboBox without changing the binding method between the DataGridView and the Departments and dropping some provided code.

ArgumentException thrown for each row

Each row was throwing the exception: "DataGridViewComboBoxCell value is not valid." Changing the following line fixed this:

colComboEmployeesByDpt.DataPropertyName = "Employees";

to

colComboEmployeesByDpt.DataPropertyName = "Employee";

Empty ComboBoxes

Now you'll notice the ComboBoxes are all empty. In the event handler OnEditingControlShowing the first if statement should check against colComboEmployeesByDpt.Index instead of colDepartment.Index . But that's not enough because if (bs != null) will always be false. Even fixing that check, control.Text is always empty. Instead, try:

BindingList<Employee> employees = repository.GetEmployeeByDepartments(this.dataGridView1.CurrentRow.Cells[colDepartment.Index].Value.ToString());

With this, you'll see each ComboBox has the correct list of employee names. However, the ArgumentException has returned. Try as I might, I couldn't fix it this time. (I suspect the ComboBox items lists were always empty, so the selected value was "invalid" .)

Answer - Restructure

To get it to work I made several core changes. I completely dropped the following:

colComboEmployeesByDpt.DisplayMember = "FullName";

private void OnEditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e)
{
  ...
}

Then I added a public property to remember the Departments, manually bound each row's employees, and hooked-up OnCellsValueChanged to refresh the lists when the Department Name changed:

BindingList<Department> Departments { get; set; }

private void OnCellsValueChanged(object sender, DataGridViewCellEventArgs e)
{
  if (e.ColumnIndex == colDepartment.Index)
  {
    this.Departments[e.RowIndex].Employees = repository.GetEmployeeByDepartments(this.dataGridView1.CurrentCell.EditedFormattedValue.ToString());
    DataGridViewComboBoxCell cell = (DataGridViewComboBoxCell)this.dataGridView1.CurrentRow.Cells[colComboEmployeesByDpt.Index];
    cell.DataSource = this.Departments[e.RowIndex].Employees;
  }
}

private void btnLoad_Click(object sender, EventArgs e)
{
  //this.dataGridView1.Rows.Clear(); // Needed if the button can be clicked repeatedly.
  this.Departments = repository.GetDepartments();

  foreach (Department department in this.Departments)
  {
    department.Employees = repository.GetEmployeeByDepartments(department.Name);

    DataGridViewRow row = (DataGridViewRow)(dataGridView1.Rows[0].Clone());

    DataGridViewTextBoxCell textCell = (DataGridViewTextBoxCell)(row.Cells[0]);
    textCell.Value = department.Name;

    DataGridViewComboBoxCell comboCell = (DataGridViewComboBoxCell)(row.Cells[1]);
    comboCell.DataSource = department.Employees;
    comboCell.DisplayMember = "FullName";

    dataGridView1.Rows.Add(row);
  }
}

This solution worked for me. When I have free time I will continue to look into fixing your original solution from the point that stumped me. Hope this helps for now.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM