I'm trying to put the cursor and focus in the last row and a specific cell with the column named 'CheckNumber'. I thought I had it with this:
var c = dataGridView1.RowCount;
DataGridViewCell cell = dataGridView1.Rows[c-1].Cells[0];
dataGridView1.CurrentCell = cell;
dataGridView1.BeginEdit(true);
but it keeps coming up with this error:
Index -1 does not have a value.
Can someone please point me in the right direction!? This is driving me nuts.
Thank you!
Ok, I am going to preface this by saying that I cannot reproduce the issue you are having. However, you mentioned that the error actually occurs at dataGridView1.CurrentCell = cell; which should have ruled out the -1 index error.
Additionally, you said that the error you get is Index -1 does not have a value. That means that even though you have the right index, cell is still coming up as index -1. This means either the cell does not exist, or something else sketchy is happening. Since you sound like you've been at this for a while, I am assuming the cell actually exists.
Since the error doesn't seem to be in any of the 4 lines you've posted I would say take a look somewhere else, like when you first bind the source to the datagridview.
Update: I just found a few links relating to this. Since I don't know how you bound your datagridview, I don't really know if any of these apply, but if any do, let us know! In any case, it seems like it may apply to binding.
From: SO Question 1
If you initially bind an empty
collection that does not inform the
DGV of changes (e.g. a Collection does
not, but a BindingList does), the
initial current row offset will be
correctly set to -1, (Because it is
empty.)
When you subsequently add objects to
your data bound collection they will
still display correctly on the grid,
but the CurrencyManager will not be
informed of any changes, and the
current row offset will remain
stubbornly at -1.
So, when you try to edit a row, the
CurrencyManager thinks you are trying
to edit a row at offset -1, and the
exception is thrown.
To combat this, you need to rebind
before interacting with a row, or
initially bind a Collection etc when
it contains one or more items.
SO Question 2
.NET Monster Question
Check the rowcount first, to make sure that you don't try to access a negative row number when there aren't any rows.
var c = dataGridView1.RowCount;
if(c>0){
DataGridViewCell cell = dataGridView1.Rows[c-1].Cells[0];
dataGridView1.CurrentCell = cell;
dataGridView1.BeginEdit(true);
}
Related
I'm having trouble trying to figure out why accessing row 0, col 3 on an HTML table isn't working. I'm using C# and Visual Studio.
While debugging if we let it pass by once and then set it back to the same line that grabs it as a variable then it would work. But never the first time through, if I went for row 1, col 3, being the next cell down one, it would grab it fine and so on with any others except for row 1 (being index 0).
Segments of the code are as follows, but we couldn't figure out why it wasn't working on specifically the first row, we even tried adding a delay to make sure the page was fully loaded and still wasn't returning any value. To remind you, it worked on every row but the first, even when the item in the first row was changed. The item in the first row, fourth col will always be changing so there is no specific class or identifier I can just access it by every time.
Any clue why it's not working for the first row and any fixes would be greatly appreciated. I have a work around, but it would just be easier to do it like this:
using Microsoft.VisualStudio.TestTools.UITesting.HtmlControls;
var browser = BrowserWindow.Launch("https://blah.com/");
var cell = GetCell(browser, 2, 3);
Console.WriteLine(cell.Value.ToString());
HtmlCell GetCell(UITestControl parent, int row, int column)
{
var cell = new HtmlCell(parent);
cell.SearchProperties.Add(HtmlCell.PropertyNames.RowIndex, row.ToString());
cell.SearchProperties.Add(HtmlCell.PropertyNames.ColumnIndex, column.ToString());
return cell;
}
Allen,
You may want to make sure that the header row of your table is of the same form as the remaining rows.
You are correct that row indexes start at 0.
You may want to try creating a debugging method. Remember that a cell is a child of a row. Pass in a table as a ui parent object and iterate through each row, then iterate through each cell and see what the debugger is showing you as values for these objects (including their types).
My suspicion is it'll be something to do with the header structure or that a element has a different object type than rather than HtmlCell
I have a data loaded from database into dataGridView, with effect looking like this:
(in final version I would prefer to hide the PatientID column)
What I'm trying to do, is return value of PatientID when user clicks ANYWHERE in the corresponding row (i.e. user clicks "Doe" and value returned is "2"). Could anyone give me a hint how to do this? I don't think there is valueMember property... I was trying Rowindex but that returns value of number of row counting from the top(D'uh?!)
Also, is there a way for user to highlight whole row when clicking on the single cell?
EDIT: Oh God, I've spent few hours late at night to find this, In the morning I gave up and posted here... just to find answer 5 minutes later:
string test = dataGridView1.Rows[e.RowIndex].Cells["PatientID"].FormattedValue.ToString();
Still, that leaves my second question about highlighting whole row.
If the datagridview is bound to some data source (DataView), you can use DataBoundItem property, for example
DGV.CurrentRow.DataBoundItem["PatientID"]
or
DGV.SelectedRows[0].DataBoundItem["PatientID"]
or
DGVUnderlyingBindingSource.Current["PatientID"]
If the DataGridView is bound to a strongly typed data source (e.g. BindingList) then you can use the above like this:
((PatientType)DGV.CurrentRow.DataBoundItem).PatientID
or
((PatientType)DGV.SelectedRows[0].DataBoundItem).PatientID
or
((PatientType)PatientTypeBindingSource.Current).PatientID
About the second part of the question, set the DataGridView's SelectionMode property to FullRowSelect
EDIT
You can't use the solution from your edit if you hide that column. In order to access the value by using .Cells[idx].FormattedValue that value must be visible. But you can use this one even if you hide the column.
For the second question, set selection mode to FullRowSelect and the complete row will be highlighted when the user clicks on it. You can set this attribute in the designer or code:
DataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect;
I have 2 DataGridViews, it´s a kind of MasterDetail tables. I have a problem with Detail DataGridView called "dgw". It´s DataSource is datatable, dgw.DataSource=DataTable;. In code I do some work with columns like change names, add some columns, dgw.Columns.Add(NewColumn); change type of column, make some columns not visible etc.
Problem is, that when I set DataSource of dgw again, which is always when the row is changed in Master DataGridView, all my work with columns in dgw is gone and I see "ugly" columns without any changes I made to them.
This is how I refresh DataSource of dgw, code is called on every change of row in MasterDataGridView.
dgw.DataSource = typeof(DataTable);
dgw.DataSource = GetVCVDataSource(dataTable);
I found some solution and I thought that 1st line should do the work but I probably did not get the idea. Before it was dgw.DataSource = null;, I used that to turn off events that happened during datasource assignment.
I believe that there must be some easy solution but I can not work it out.
Thank you for any advice.
I suspect the first line in there is hurting you; the following would be more appropriate:
xx.DataSource = null;
xx.DataSource = GetVCVDataSource(dataTable);
Which will rebind without having to worry about a different type in the middle.
Also, at some point earlier (once only):
xx.AutoGenerateColumns = false;
I have a DataGridView bound to a list of custom objects created on the fly. This list is not very large, 5000 items maximum. However, the values of the custom objects change every 50ms and the grid hangs the application while refreshing the values and it ultimately crashes.
My question is: is there a way to "virtualize" the data binding of the DataGridView so that only the rows that are actually seen on the screen are refreshed?
EDIT: I found out why my DataGridView was so slow and it had nothing to do with data binding. So this question is no longer relevant. As a side note, I think the DataGridView already refreshes only the visible rows when a ListChanged event occurs.
A good article on Virtual mode (DataGridView). - http://www.codeproject.com/KB/books/PresentDataDataGridView.aspx#7
Spent quite a while searching this issue and this question kept popping up, so I'll link here the answer which solved my problem: https://stackoverflow.com/a/9348149/674884
I have a DataGridView bound to a BindingSource which is also bound by ComboBoxes and TextBoxes used to edit the data. Every Leave event on the editors had a big lag which was caused by the DataGridView redrawing all it's rows when the data was updated. This happened even when using VirtualMode.
The problem was caused by the AllCells autosize setting of DataGridView columns. Every time a value changed the DataGridView went through all the rows to find the longest string for autosizing the column. After disabling autosizing I realized that even the databound DataGridView draws only the visible rows, so no need to use the VirtualMode.
I think you will want to look into using the DataGridView in virtual mode.
What is stopping you just pulling the visible sub-set of items instead of the full 5000?
I don't know if ListChanged already refreshes only the visible rows.
I can't see any indention in MSDN. I will look into DataGridView implementation later and update.
Anyhow the follow works for me:
int scrollPositionFirst = dataGridView1.FirstDisplayedScrollingRowIndex;
// displayedRowCount -> is our visible rows count
var displayedRowCount = dataGridView1.DisplayedRowCount(false);
// the loop will iterate in the amount of the displayed rows
for (int rowCount = 0; index < displayedRowCount; rowCount++)
{
// scrollPositionFirst is our first visable row
// so scrollPositionFirst is our starting point
var set = (Set)dataGridView1.Rows[scrollPositionFirst].DataBoundItem;
// we update the grid from the first visable(displayed) index
UpdateMainGrid(scrollPositionFirst, set);
// increment index -> this is done because we want to update the next visible row
scrollPositionFirst++;
}
As a question similar to this question, I also have an application with a DataGridView on it. I would like to position the rows such that a specific row is at the bottom of the visible part of the list.
This is in response to a button click that moves a row down by one. I want to maintain the selection on the row I'm moving (I already have this part working). If there are lots of rows, the selected row might move below the visible area. I want to scroll down until it's at the bottom of the visible area.
There does not appear to be a LastDisplayedScrollingRowIndex companion to FirstDisplayedScrollingRowIndex.
Any ideas? Thanks.
As my own guess, I think I need to use FirstDisplayedScrollingRowIndex and the number of rows visible in the DataGridView to calculate the new FirstDisplayedScrollingRowIndex. Maybe I just need to find out what the NumberOfVisibleRows property is called?
Found it. DisplayedRowCount:
if (dataGridView.FirstDisplayedScrollingRowIndex + dataGridView.DisplayedRowCount(false) <= selectedRowIndex)
{
dataGridView.FirstDisplayedScrollingRowIndex =
selectedRowIndex - dataGridView.DisplayedRowCount(false) + 1;
}
Code tested and working in my own project.
The DisplayedRowCount method will tell you how many rows are displayed on screen. Set the parameter value to true to include partial rows.
var displayedRows = myDataGridView.DisplayedRowCount(false);