C# DataGridView multiple selections get overwritten - c#

I'm running into a problem making multiple selections programmatically in a DataGridView (DGV) based on data table values. I have a table with one column "ID", I need to pass these values to another form with a DGV for editing, ID is the first DGV column also, i.e. for every ID in the table, the appropriate DGV row should be selected.
I can loop through the table and DGV fine, but only the last value is selected even though the DGV properties MultiSelect=true ... when I use the form manually, multiple select works fine.
foreach(DataRow dtrow in dt.Rows)
{
string Selection = dtrow["ID"].ToString();
foreach(DataGridViewRow DGVrow in dgview.Rows)
{
if (DGVrow.Cells[0].Value.ToString().Equals(Selection))
{
dgview.CurrentCell = DGVrow.Cells[0];
int cellInx = dgview.CurrentCell.RowIndex;
dgview.Rows[cellInx].Selected = true;
break;
}
}
}

I'm answering my own question because I don't think this is possible on form load. My application has a form that's used to add selections to a project. When the user wants to 'Edit' the project, I need to call this form and make all the previous selections so the user can add/delete.
When using a DataGridView (DGV) with multi-select enabled, at run time, you can 'ctl-click' and select multiple items ... essentially I'm trying to recreate this behavior in code, on form load in 'edit' mode.
After the form is initialized I have a method that loads the DGV from OleDb tables, to test this out I tried putting the following lines after the load method call and as the last lines of the method call:
dgv1.Rows[0].Selected = true;
dgv1.Rows[1].Selected = true;
dgv1.Rows[2].Selected = true;
Obviously, on form load, I was expecting the first 3 rows to be 'selected', but that didn't happen.
However, I remembered a separate issue, I could never get the DGV to load without the first line selected by default ... so I put in a 'refresh' button, that simply calls the 'Load' method again ... the last line of which is: DGV1.Rows[0].Selected = False; With the refresh button the DGV loads without the first line selected.
I was curious if this was a similar situation, so when I added these 3 lines to the end of the load method, nothing happened on form load ... but ... when I hit the 'Refresh' button, the first 3 rows were 'selected'.
I've been researching this for over 3 days and found the following from the DataGridView Project Manager (2006):
https://social.msdn.microsoft.com/Forums/windows/en-US/cf351d44-4a9a-4c80-8d52-4fb349847908/multiple-select-is-not-working-for-datagridview?forum=winformsdatacontrols
Unfortunately there isn’t an easy solution to this as I didn’t look at this scenario and design the grid to handle this well. The main problem stems from the fact that when you mouse down on the grid, the grid sets the current cell property which clears the selection before selecting the next cell/row/column. So, while your line of code selects the row, when you go to select the next row or just move to the next row using the keyboard, the row you selected is cleared. The easiest way to do your scenario is to use custom painting via the RowPrePaint and paint the “selected” rows using the same SelectedBackground color. You can just query the value of the check box cell in the row that you are painting to know if that row is “selected”, but there isn’t any need to set the Selected property to true. The flip side to this is that you’ll have to keep track or enumerate all rows to know all the “selected” row at a given time.
-> mark -> DataGridView Program Manager - 2006
So my plan going forward is to rebuild the DGV to use check boxes, as recommended. I just wanted to put this out there for general information and/or if someone has a better idea. Thanks

Related

How to remove DataGridView last row ButtonColumn Button c#?

I am doing a windows application in c#.
Can any one help me to solve this issue. I have use datagridview in my form which is contain ButtonColumn and 3 other columns. generates the form with total values of the columns in last row. problem is I want to remove the Button Column Button in Last row (Grand Total row).
In here I have use local database table as a data source for the DataGridView. Please help me.
This is the output
You may try to reach for that cell after data is loaded and make it "less button". Following code comes from the top of my head and hasn't been tested, but it is just worth trying.
int DetailColumnIndex = 0; //or whatever it is
var LastButtonCell =(DataGridViewButtonCell)myDataGridView.Rows[myDataGridView.Rows.Count-1]
.Cells[DetailColumnIndex];
LastButtonCell.Value = null;
LastButtonCell.FlatStyle = FlatStyle.Flat;
Then make sure that when it is clicked, the eventhandler detects that it is the last button and does nothing

How does one get rid of this design-time row in the DataGridView row at run-time?

I'm using a DataGridView in a WinForm for the very first time, and have run into an odd problem.
I'm trying to populate the DataGridView control from the database. I'm not binding it to a dataset or anything, but retrieving a set of rows from a Sqlite query. I am then populating the rows programmatically from the data retrieval result. The grid is set up like this (as it appears in the designer):
What happens at runtime is fine, except for what appears to be a "phantom" row, which shows up in the grid as it appears in the designer, as the last row (blank or unpopulated), when I finish loading the grid. I've tried clearing the rows:
DataGridView.Rows.Clear();
But this doesn't clear anything. Trying to remove or make this row invisible fails with an exception because it's apparently uncommitted.
How do I get rid of the thing?
After entering the question in its entirety, I tried one last time to see if there was something that stood out. So I examined the properties of the DataGridView in close detail and wondered about some of the properties whose function I wasn't sure about.
The answer turned out to be the property AllowUserToAddRows. The "uncommitted row", as the exception designated it, is the place where the user would add the information for a new row that is to be inserted! Since this implementation of the grid is intended to be for editing of existing rows only, setting this property to False removed the apparently "bogus" row, and solved my problem.
And incidentally removed the row from the designer.

How to make last row in a dataGridView on a Windows Form to be displayed all the time while still allowing the remaining rows to scroll

I have a dataGridView which has about 30 rows in it and last row of it contains sum of all the cells in that particular column. Now I would like to freeze the last row which has sum while still allowing the remaining rows to scroll.
dataGridViewPaymentsReceived.Rows[dataGridViewPaymentsReceived.Rows.Count-1].Frozen = true;
The above code freezes the entire dataGridView and doesn't allow me to scroll on it.
Can anyone suggest me a good way to keep the last row displayed all the time even when I scroll on the dataGridView?
The easiest solution would be to create a second DataGridView directly below the first. Then manually populate it with the single row that you want to be displayed every time the first datagrid binds to data.
To make it appear totally seamless, don't forget to hide the column headers in the 2nd datagrid:
dataGridView2.ColumnHeadersVisible = false;
See this answer for more info.

Datagrid on demand load off

I have a SDK:DATAGRID with 20 columns or so, when it opens up it only shows four fields/columns. Which is what I want and how I designed it
Basically I'm grabbing information based on the user click - EXAMPLE:
OWNERNAME.Text = ((TextBlock)EPICGrid.Columns[1].GetCellContent(EPICGrid.SelectedItem)).Text;
and/or
OWNERNAME2.Text = ((TextBlock)EPICGrid.Columns[16].GetCellContent(EPICGrid.SelectedItem)).Text;
What I'm running into it doesn't grab the information in the cell unless if I scroll and show the column so I can only grab the first 4 columns of data because they show when the grid becomes visible.
I can't grab data from columns 5 -20 unless I scoll over and make those columns visible. They don't have to be visible during the click...it just seems like the data doesn't really load until I view the column.
I guess I should say the first record/row loads all the data/cells/columns and I can grab any data from the first record but the problem happens with records 2 - *.
Just to clarify - my issue is not a visibility of my columns or rows. My issue is the SDK DataGrid seems like it is loading the data on demand. So if the column is not in view at one point or another the information in the cell is not available.
I don't want to show all columns and I don't want to give the user the ability to see all columns so I want to disable the scroll bars but when a user clicks on a certain row I need to grab information in certain cells and since the column is not load yet the information is not there.
How do I turn the feature load on demand off?
I did a search and found out that someone had a similar problem with rows loading and the suggestion was setting the VirtualizingStackPanel.VirtualizationMode = Standard
It almost like the problem is stemmed from VirtualizingStackPanel.VirtualizationMode but I set this property to standard and recycle and no luck.
Here's definition:
By default, a VirtualizingStackPanel creates an item container for
each visible item and discards it when it is no longer needed (such as
when the item is scrolled out of view). When an ItemsControl contains
a lot of items, the process of creating and discarding item containers
can negatively affect performance. When
VirtualizingStackPanel.VirtualizationMode is set to Recycling, the
VirtualizingStackPanel reuses item containers instead of creating a
new one each time.
On initial load, if the cell is not visible I can not grab the cells
content (unless it is the first record/row). Once and after the cell /
column is visible then the information is available.
I think you are expected to deal with the data that the row is bound to directly and not pull the data out of the controls. This makes sense since it is two way data binding so the data is updated as you are changing it (assuming it implements the INotifyPropertyChanged Interface).
An example would be where a datagrid is bound to a collection of type MyEntity.
private void DataGrid1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (this.DataGrid1.SelectedItem == null)
return;
MyEntity myEntity = (MyEntity)this.DataGrid1.SelectedItem;
// at this point you have the (updated) data the row is bound to.
MessageBox.Show("You Selected: " + myEntity.name);
...
Another example is where there is a button on each row. The code to process when a button is clicked looks something like:
private void btnProcessEntity_Click(object sender, RoutedEventArgs e)
{
Button btn = sender as Button;
MyEntity myEntity = btn.DataContext as MyEntity;
// clicking a button in a row doesn't select the row, so select it.
this.DataGrid1.SelectedItem = myEntity;
MessageBox.Show("Will Process: " + myEntity.name);
...
}
If you are not familiar with some of the technologies that normally are used with Silverlight check out these Video Tutorials. It is VB.Net, but the code is really not the focus - it is focused on a Silverlight application architecture. I would start with "Intro to SL4 and WCF Ria Services" and then view one of the ones on MVVM.

How can I refresh only the visible rows of a data bound DataGridView?

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++;
}

Categories

Resources