0

I'm trying to put 3 binded DataGridViewComboBoxCell in my datagridview,

one for 'Categorie' table, the second for 'Article' table and the third for

'ArticleNonCon' table. when i select a categorie the second

DataGridViewComboBoxCell should give me the articles of this categorie and

when i select an article the third DataGridViewComboBoxCell should give me

the serial numbers of this article. This is the code i tried:

in the button click that shows the form:

if (con.State != ConnectionState.Open)
{
    con.Open();
}

SqlCommand catCmd = new SqlCommand("SELECT IdCategorie, LibCategorieFr FROM Categorie", con);
DataTable catDt = new DataTable();
catDt.Load(catCmd.ExecuteReader());
((DataGridViewComboBoxColumn)dataGridView1.Columns["CategorieColumn"]).DataSource = catDt;    
((DataGridViewComboBoxColumn)dataGridView1.Columns["CategorieColumn"]).DisplayMember = "LibCategorieFr";
((DataGridViewComboBoxColumn)dataGridView1.Columns["CategorieColumn"]).ValueMember = "IdCategorie";

and in CellEndEdit event of the datagridview:

private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
    switch (dataGridView1.Columns[e.ColumnIndex].Name)
    {
        case "CategorieColumn":
            if (con.State != ConnectionState.Open)
            {
                 con.Open();
            }
            SqlCommand artCmd = new SqlCommand("SELECT * FROM Article WHERE IdCategorie = @IdCategorie", con);
            artCmd.Parameters.AddWithValue("@IdCategorie", dataGridView1.CurrentRow.Cells["CategorieColumn"].Value);
            DataTable articleDt = new DataTable();
            articleDt.Load(artCmd.ExecuteReader());
            ((DataGridViewComboBoxColumn)dataGridView1.Columns["Column3"]).DataSource = articleDt;
              ((DataGridViewComboBoxColumn)dataGridView1.Columns["Column3"]).DisplayMember = "LibArticleFr";
            ((DataGridViewComboBoxColumn)dataGridView1.Columns["Column3"]).ValueMember = "CodeArticle";
            con.Close();
            break;

       case "Column3":
           if (con.State != ConnectionState.Open)
           {
               con.Open();
           }

           SqlCommand numSerieCmd = new SqlCommand("SELECT * FROM ArticleNonCon WHERE CodeArticle = @CodeArticle", con);
           numSerieCmd.Parameters.AddWithValue("@CodeArticle", dataGridView1.CurrentRow.Cells["Column3"].Value);
           DataTable numSerieDt = new DataTable();
           numSerieDt.Load(numSerieCmd.ExecuteReader());
           ((DataGridViewComboBoxColumn)dataGridView1.Columns["NumSerieColumn"]).DataSource = numSerieDt;
           ((DataGridViewComboBoxColumn)dataGridView1.Columns["NumSerieColumn"]).DisplayMember = "NumSerieArticle";
           ((DataGridViewComboBoxColumn)dataGridView1.Columns["NumSerieColumn"]).ValueMember = "id";
           con.Close();

           break;
    }
}

This code works perfectly for the first run, but whent i try to change the article and select the serial numbers of this article from the third datagridviewComboboxCell i got this exception:

System.ArgumentException:DataGridViewComboBoxCell value is not valid

This exception occured also when i try to close the application.

So how to fix this error or in which datagridview event i should put my code?

Thanks in advance.

stefankmitph
  • 3,236
  • 2
  • 18
  • 22
user4428204
  • 123
  • 3
  • 5
  • 12

1 Answers1

0

Assuming you have a DataGridView with no existing data at all. You have to create data anyhow. In your case it could be a class with just 3 properties

public class MyDataSource 
{
    public int CategoryID { get; set; }
    public int ArticleID { get; set; }
    public int ArticleNonCon { get; set; }
}

We also need some classes that represent our ComboBox datasource:

public class Category
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public class Article
{
    public int ID { get; set; }
    public string Name { get; set; }
}

public class ArticleNonCon
{
    public int ID { get; set; }
    public string Name { get; set; }
}

This class (as a list of it) will be attached to your DataGridView and IS your DataSource (it will store the ValueMembers of your ComboBoxes). Put following code into a initialize method:

List<MyDataSource> listMyDataSource = new List<MyDataSource>() // it's an empty list of MyDataSource

dataGridView1.AutoGenerateColumns = false; // prevent DataGridView from adding columns we don't want to have

dataGridView1.DataSource = new BindingList(listMyDataSource); // this is very important as we want to add new rows to our DataGridView. Adding just a list object wouldn't allow this 

Now we have to create the datasources for our ComboBoxColumns:

List<Category> listCategories = new List<Category>
{
     new Category { ID = 1, Name = "Category1"},
     new Category { ID = 2, Name = "Category2"},
     new Category { ID = 3, Name = "Category3"},
};

List<Article> listArticles = new List<Article>
{
    new Article { ID = 1, Name = "Article1"},
    new Article { ID = 2, Name = "Article2"},
    new Article { ID = 3, Name = "Article3"},
};

List<ArticleNonCon> listArticlesNonCon = new List<ArticleNonCon>
{
    new ArticleNonCon{ ID = 1, Name = "ArticleNonCon"},
    new ArticleNonCon{ ID = 2, Name = "ArticleNonCon"},
    new ArticleNonCon{ ID = 3, Name = "ArticleNonCon"},
};

This is of course just sample data... so fill it with your data from the database.

Now we add the columns to the DataGridView:

dataGridView.Columns.Add(new DataGridViewComboBoxColumn
{
    Name = "CategoryColumn",
    DataSource = listCategories,
    ValueMember = "ID",  // property of our class Category
    DisplayMember = "Name", // property of our class Category
    DataPropertyName = "CategoryID" // bind it to the property CategoryID from our class MyDataSource
});
...

The same goes for Article and ArticleNonCon.

One thing you'd have to do: Subscribe to the DataError event of your DataGridView (otherwise you will get an exception when trying to add a new row with empty data).

dataGridView.Columns.Add(new DataGridViewComboBoxColumn
{
    Name = "ArticleColumn",
    DataSource = listArticles,
    ValueMember = "ID",
    DisplayMember = "Name",
    DataPropertyName = "ArticleID"
});

This should do. (and that's the way to bind and display data in Winforms)

stefankmitph
  • 3,236
  • 2
  • 18
  • 22