0

So.... I have created a new project, I have added a database and dataset, created a table, populated it, set it as a data source, and finally have pulled a 'details' and 'datagridview' onto my form.

I have tested these and all displays just fine.

Now the problem. I want to call a cell value and then carry out a task based on the result, but everytime I try, I get an out of range exception.

I've looked around at other topics and tutorials and similar questions and it suggests that I'm trying to call a cell that doesnt exist. This doesnt make sense, as I've tried various low-number index combinations, and my table consists of 4 columns and 16 rows, all of which contain data.

All other indicators point to the program not understanding that the datagridview actually contains data - as if it wants to me to define it before it can call the data - but this makes no sense to me because I've pulled it from a database and I can view the data with no problems when I run the program.

I've tried various different codes to call on a cell, but I get the same exception every time.

int testValue1 = (int)islandMapDataGridView[1, 1].Value;
Console.WriteLine(testValue1);

I should point out that I'm reasonably new to this. What am I doing wrong?

EDIT - Thank you for pointing me to a similar question with a lengthy answer - unfortunately I've looked at many just like this already. They are suggesting that I'm picking a cell that does not exist.

I am aware that these indexes start at 0 and I should compensate for this. Again, my datagridview has 4 columns and 16 rows. I am (for example) attempting to get the data at cell index 1,1 - which is well within the range of the datagridview.

The problem does not seem to be that I am calling a cell that falls outside the range of cells and rows in the datagridview but rather that it seems to think that nothing is there at all. But if I disable the line of code that is supposed to return the value - when I run the program I can see the table just fine and the data is there.

If I have to take the time to define the datagridview just so I can call a value from a cell, then what was the point in setting up databases, datasets, datasources and tables in the first place?

2nd EDIT - What do I have to do to get this looked at again????? Somebody has stated this is an exact duplicate of another question, and linked me to it. It is NOT an exact duplicate. I am NOT trying to reference a cell that falls outside of the datagridview. The problem seems to be that the datagridview is not properly reporting back the data contained within in. Presumably I have missed some sort of initialisation, or there is something wrong with the binding.... I dont know... If I knew, then it wouldnt be a problem. The linked topic/question does nothing to explain what I am missing. Please can I get some help with this? Please?

3rd Edit - I'd like to add that since my opening question, I've been looking around and trying to find a solution - I stumbled across a tutorial carrying out a similar exericse, and they included the following line of code:

islandMapDataGridView.SelectionMode = DataGridViewSelectionMode.CellSelect;

I hoped this might resolve my problem, but sadly it did not.

I am guessing that something fundamental is missing that allows me to report values from the datagrid, or it is somehow not properly loaded or configured.

I would appreciate any help - even if just to point me a tutorial or similar which expains how to set this sort of thing up.

Do I need to set up a class in order to fetch a value from a cell? Do I need to set up a database context? Please, what am I missing here?

4th Edit! - Ok so here is the code that was automatically generated by the program when i dragged in the 'datagridview' and 'details' from the table in datasources.

private void islandMapBindingNavigatorSaveItem_Click(object sender, EventArgs e)
    {
        this.Validate();
        this.islandMapBindingSource.EndEdit();
        this.tableAdapterManager.UpdateAll(this.starterIslandDataSet);
    }

    private void Form4_Load(object sender, EventArgs e)
    {
        // TODO: This line of code loads data into the 'starterIslandDataSet.IslandMap' table. You can move, or remove it, as needed.
        this.islandMapTableAdapter.Fill(this.starterIslandDataSet.IslandMap);
    }

There doesnt appear to be anything specifically here for the datagridview - but again, when i run the program, it displays it just fine, including all the information that i entered into the table.

Here is the code I am trying to use to pull info from the database -

private void MapTilesTest()
    {
        islandMapDataGridView.SelectionMode = DataGridViewSelectionMode.CellSelect;

        foreach (Control control in tableLayoutPanel2.Controls)


            {
            PictureBox maptile = control as PictureBox;
            if (maptile != null)

            {
                int testValue1 = (int)islandMapDataGridView[1, 1].Value;
                Console.WriteLine(testValue1);

            }

        }

I am using console.writeline just to confirm that i can indeed pull a value from the table.

I have looked at tutorials for advice, and i see lots where they are manually coding the datagridview and manually inputting the data into the datagridview in the code - i assume this is one way of doing it - but i cant find a good example where someone is pulling information from a database in the same way.

Martyn
  • 17
  • 5
  • Can somebody please help me with this??? The problem is NOT that I am attempting to retrieve data from a cell that does not exist - the problem seems to be that the program doesnt recognize that the cell holds data to begin with! – Martyn Aug 17 '17 at 07:00
  • Can anyone help? Do i need to set a database context or something like this? Any assistance would be appreciated. I wish this topic had not been closed - I am sure Peter meant to be helpful but I am sure he has misunderstood the problem and just skim read my question and closed it. – Martyn Aug 17 '17 at 08:14
  • Thankyou to whoever unmarked this as a duplicate. – Martyn Aug 17 '17 at 10:39
  • Without seeing more code it would be difficult to give a good answer. I am guessing the problem may be related to “WHERE” the line `int testValue1 = (int)islandMapDataGridView[1, 1].Value;` is called? This is missing from the post and is important. Example, if the line `islandMapDataGridView[1, 1]` is inside the `DataGridViews_RowsAdded` event, then your error makes perfect sense. When you set the data source, and the first row is added, its index will be zero (0) at which point the line `islandMapDataGridView[1, 1]` will be out of range and fail because there is no row at index “1”. – JohnG Aug 19 '17 at 07:12
  • Hi John - Thanks so much for replying, I appreciate the help! - I've had a look through my code, and I have no line of text for DataGridViews_RowsAdded - I have literally just brought the datagridview in from the database. Since I can run the program and can see the datagridview and the data that I entered is being displayed, I was assuming (and I could well be mistaken!) that the table 'worked' for want of a better description - – Martyn Aug 19 '17 at 08:52
  • IE i can see that adding the database and the datagridview automatically added some other code, so I figured the datagridview must be set up too. Are there some steps I need to take to correctly set it up? I am sorry if this appears to be a dumb question or something painfully obvious. – Martyn Aug 19 '17 at 08:52
  • To elaborate on my previous comment about the datagridview 'working' - I mean that if the program can already load and display the information in the datagridview, why can I not just as easily pull a value from the datagridview? If something is missing, I'd be pleased to know/understand what and why. – Martyn Aug 19 '17 at 08:58
  • You should show the code that fills the grid and you should show the code WHERE the line is being called. To be more specific… where is the line `int testValue1 = (int)islandMapDataGridView[1, 1].Value;` being called? What method is that line in? – JohnG Aug 19 '17 at 09:07
  • I'll add a 4th edit to the original question. Thanks John – Martyn Aug 19 '17 at 09:20
  • At what point are you calling MapTilesTest()? Just for test purposes, try adding a button to your form which calls MapTilesTest, which you only click when you can see the DataGridView with records in it. – Jonathan Willcock Aug 19 '17 at 10:41
  • Jonathan Willcock - welcome to the party! And can I just say... I love you! Bizarrely, that works (I wasn't actually expecting it to because I'd reached the conclusion that I was missing some fundamental step) - I had that event set to run as soon as the form opens. I moved it to a button as you suggested, and now it correctly returns the values. Obviously my previous attempt was trying to collect the information before it was loaded! However.... there is one slight problem! I do want the event to take place when the form is loaded. So my next comment...... – Martyn Aug 19 '17 at 10:53
  • Seeing as how I do want the event to take place automatically, is there some way I can defer this event until after the datagridview has properly populated with data - or can I somehow assign preference to that happening before my event collects the data? – Martyn Aug 19 '17 at 10:54
  • Sorry - further comment - the event does not HAVE to take place when the form loads exactly - but I do want it to be an automatic thing, preferably as soon as the datagridview is ready to feed out cell values. I don't really want it to be something you have to click to activate (But I'm very glad that the test proves the datagridview works in the way I initially hoped it would!). Any advice on how to implement this? – Martyn Aug 19 '17 at 11:31
  • Nevermind! I have found the way! `private void Form4_Load(object sender, EventArgs e) { // TODO: This line of code loads data into the 'starterIslandDataSet.IslandMap' table. You can move, or remove it, as needed. this.islandMapTableAdapter.Fill(this.starterIslandDataSet.IslandMap); MapTilesTest(); }` I tested this and works just fine!! Thanks again for your help John and John - is there anyway I can give you both a positive rating or big thumbs up? – Martyn Aug 19 '17 at 11:36

1 Answers1

0

After reading the comments, it may be helpful to clarify some major points in what you are trying to accomplish. First is the reality that when you try to access a cell’s value in a grid, it is imperative that you check several possibilities.

First, does the cell actually exist? In your posted example, you are trying to access the value from the cell at row 1 column 1. This can be accomplished by simply checking to make sure the grid has at least two (2) rows and at least two (2) columns. If you do not check this, and the grid has less than two (2) rows or less than two (2) columns… your code will crash and burn. This obviously is a bad thing and “you” as a programmer should ALWAYS assume the possibility that the cell you are looking for does not exist, is null or the cells value is not a number.

If you have not done so yet, I recommend you take a look at the Try/Catch construct. This useful construct will allow you to TRY some part of your code and CATCH any errors… like an index out of range error. The try catch construct is useful to catch errors and respond to them. In your posted code there would be three possible errors in the line int testValue1 = (int)islandMapDataGridView[1, 1].Value; And you would want to catch all these possible errors in the following order.

1) The cell at row 1 column 1 does not exist.

2) The cells “Value” at column 1 row 1 is null.

3) The cells “Value” at column 1 row 1 is not a number.

The line int testValue1 = (int)islandMapDataGridView[1, 1].Value; could produce one of the three errors above. If the cell does not exist, is null or is not a number, then there would be no value to output.

The convenient aspect of the Try/Catch is that you can “catch” all errors or specific errors. Example, the code below will catch all three possible errors.

private void MapTilesTest() {
  try {
    int testValue1 = (int)islandMapDataGridView[1, 1].Value;
    MessageBox.Show("Value is: " + testValue1.ToString());
  }
  catch (ArgumentOutOfRangeException ex) {
    MessageBox.Show("Cell 1,1 does not exist: total rows = " + islandMapDataGridView.Rows.Count + " total colums = " + islandMapDataGridView.Columns.Count);
  }
  catch (NullReferenceException ex) {
    MessageBox.Show("The 'Value' at Cell 1,1 is null (most likely the new row): total rows = " + islandMapDataGridView.Rows.Count + " total colums = " + islandMapDataGridView.Columns.Count);
  }
  catch (InvalidCastException ex) {
    MessageBox.Show("The 'Value' at Cell 1,1 is NOT a number or is an empty cell: actual cell value is: " + islandMapDataGridView[1, 1].Value.ToString());
  }
  catch (Exception ex) {
    MessageBox.Show("Some other error: " + ex.GetBaseException());
  }
}

A second approach is to manually check for these errors. The code below demonstrates this and also uses an int.TryParse construct to validate if the value in the cell is actually a number. Using a TryParse is a better way to convert strings to numbers and validate the string is actually a number. Casting a string to an int as your code does, ALWAYS has the possibility of failure and should ALWAYS be checked. The Try/Parse construct helps in this checking.

The code below still uses a Try/Catch however the difference is that the code below is manually checking for the specific errors: index out of range, a null cell value and valid integer string values. These error checks are made BEFORE they happen and therefore the exceptions will not be thrown. If there are ANY other exceptions thrown… the catch clause will get them.

private void MapTilesTest() {
  try {
    // make sure there are enough rows
    if (islandMapDataGridView.Rows.Count < 2) {
      MessageBox.Show("Row Index is out of range: total rows = " + islandMapDataGridView.Rows.Count);
      return;
    }
    // make sure ther are enough columns
    if (islandMapDataGridView.Columns.Count < 2) {
      MessageBox.Show("Column Index is out of range: total columns = " + islandMapDataGridView.Columns.Count);
      return;
    }
    // make sure the cells value is not null
    if (islandMapDataGridView[1, 1].Value == null) {
      MessageBox.Show("Value is null (most likely the new row)");
      return;
    }
    // Make sure the cells value is actually an integer
    int testValue1 = 0;
    if (int.TryParse(islandMapDataGridView[1, 1].Value.ToString(), out testValue1)) {
      MessageBox.Show("Valid Value is: " + testValue1.ToString());
    }
    else { 
      MessageBox.Show("Value is not a number: " + islandMapDataGridView[1, 1].Value.ToString());
    }
  }
  catch (Exception ex) {
    MessageBox.Show("Error: " + ex.Message);
  }
}

I hope this makes sense. Lastly, I can assure you that the error you are getting is coming from when the data is being filled into the grid. Obviously, when the first row is filled with data, your code will crash without these checks and this is exactly what is happening. When I asked you to show where the line is being called and you responded with it is being called in the method MapTilesTest, does not help. We need to know WHEN is the MapTilesTest method called in relation to when the grid is filled. I can only assume that MapTilesTest is getting called (before or during) when the grid is filled with data and therefore will cause the error you describe as soon as the first row is added to the grid.

JohnG
  • 9,259
  • 2
  • 20
  • 29
  • JohnG - Thanks very much for your answer, very useful advice you have given, I will be sure to make use of it! One question I do have, which you touched on briefly, is about casting a string to an int value. I noticed this was happening with the value I tried to call from the datagridview - but I had formatted/configured that column to store int values. Does reporting a cell value return string values by default? Is there a work-around for this (if one should become necessary? - it hasnt affected me so far). Thanks again for your valued help and assistance! – Martyn Aug 20 '17 at 05:36
  • If the grids data source’s data type for that column is an integer, then you should be ok. The reason you need to `cast` with the line `int testValue1 = (int)islandMapDataGridView[1, 1].Value;`… isn’t necessarily converting a string to an int. The “Value” returned is an “object”. You could cast it to any type you like. If the column type and the cast type match, as your `int` column and `int` cast do, then things should be ok, however, you should still check for null or empty values as they will cause the cast to fail. Hope that makes sense. – JohnG Aug 20 '17 at 07:24