How to stop data grid adding additional row? - c#

I'm populating datagrid view like this.
var dataTable = new viewregisterdVotersOP().getTableRegVoters(lgdiv, elecid);
if (dataTable == null || dataTable.Rows.Count == 0)
{
tempmsg1 = "Couldn't find data in the system";
setErrorMSG(tempmsg1);
}
else
{
dgvView.DataSource = new viewregisterdVotersOP().getTableRegVoters(lgdiv, elecid);
}
But it adds an extra empty row. How to stop that?

But it adds an extra empty row. How to stop that?
That row is there to allow users to add new rows to grid, you can disable that either in code behind or at design view using DataGridView.AllowUserToAddRowsproperty
In code behind:
dgvView.AllowUserToAddRows = false;
Or set the property to false in design view.

Related

How do I hide an entire DataGridview Row if Column index 0 contains a specific string C#

What I've done so far
DataSet dataSet = new DataSet();
dataSet.ReadXml(dialog.FileName);
dataGridView1.DataSource = dataSet.Tables[0];
MessageBox.Show(this.dataGridView1.Columns["Visible"].Index.ToString());//To hide -returns 0
foreach (DataGridViewRow dr in dataGridView1.Rows)
{
if (dr.Cells[0].Value.ToString() == "False")
{
dr.Visible = false;
}
}
The gridview
I'm trying to hide the entire Row where the Visible Column value is False
After some research, I am confident that you will be better off “filtering” the grids DataSource as opposed to setting the individual grid row’s Visible property to false.
The biggest problem you will have in doing this… is that you CAN NOT set the grids CurrentRow Visible property to false. This will throw an exception that complains along the lines of …
”Row associated with the currency manager's position cannot be made invisible”
… basically this is saying the grid's CurrentRow cannot be invisible.
Considering this, it would appear that this approach may not work since at least ONE (1) row in the grid will be the CurrentRow and your code will fail if the grid's CurrentRow “Visible” cell is set to “False.”
In addition, to exploit the testing parameters… what if ALL the rows are “False”? … In that case the exception is guaranteed since at least ONE of the rows will be the CurrentRow.
Hopefully, this may explain “why” your code may work some times and not at other times.
Therefore, I suggest a simple solution that avoids the grids currency manager all together. This can be done by filtering the grids DataSource. Something like the button click event below…
private void button1_Click(object sender, EventArgs e) {
DataView dv = new DataView(dataSet.Tables[0]);
dv.RowFilter = "Visible = True"; // <- filter rows that have True in the Visible column
dataGridView1.DataSource = dv;
}
It is unclear “where” the posted code in your question is executed, however in my solution above it will make things easier if you make dataSet or at least dataSet.Tables[0] a “GLOBAL” variable. Reason being that when you use the DataView.RowFilter and then set the grids data source to the DataView… then unless you have access to the original table dataset.Tables[0]… you will not be able to “un-filter” the grid and instead you would need to re-query the DB. I hope that makes sense. Good Luck.
The main problem here, I think, is that you are replacing the Visible value of the row, instead of the row of the Datagrid. Replace the foreach with a for:
for(int i=0; i <= dataGridView1.Rows.Count();i++) {
dataGridView1.Rows[i].Visible = Convert.ToBoolean(dataGridView1.Rows[i].Cells[0].Value);
}
What is the value of dr.Cells[0].Value.ToString() when you get that row? Check it with debugger and quickwatch. Maybe is not "False" as you show it.
The main idea is get any kind of false with Convert. And also you don't need the if at all.
if (Convert.ToBoolean(dr.Cells[0].Value))
{
dr.Visible = false;
}
And also you don't need the if at all.
dr.Visible = Convert.ToBoolean(dr.Cells[0].Value);
You may use the DataGridView CellPainting event.
Everytime a cell in dataGridView1 needs repainting the event is fired.
The good thing is that this event will fire when the dataGridView1 is initialized and when the user leaves a cell. Hence this solution will remove the arbitrary rows when the DataGridView is initializing (and then remove any loaded rows with "False" in column 0) but also remove any rows that are changed to "False" by the user during run time.
private void dataGridView1_CellPainting(object sender, DataGridViewCellPaintingEventArgs e)
{
if (e.ColumnIndex < 0 || e.RowIndex < 0)
return;
if (dataGridView1.Rows[e.RowIndex].Cells[0].Value == null) //Return if cell value is null
return;
if (e.ColumnIndex == 0) //Current cell to paint is in visible column
{
DataGridViewRow currentRow = dataGridView1.Rows[e.RowIndex]; //Row of current cell
if (currentRow.Cells[0].Value.ToString() == "False")
{
currentRow.Visible = false;
}
}
}
Either add the event at the events list in the Design view or add it directly to the designer class for the control containing dataGridView1
//
// dataGridView1
//
...
this.dataGridView1.Name = "dataGridView1";
this.dataGridView1.CellPainting += new System.Windows.Forms.DataGridViewCellPaintingEventHandler(this.dataGridView1_CellPainting);
...

Two different datagridview rows getting selected when one should be selected

I am working with winform project. i have two datagridview which has same number of columns and same structure. frist column is checkbox column.
here is code to bind two datagrid with same kind of data.
List<AllGroupNames> grpDtl = GetAllGroups(Nodes);
List<AllGroupNames> grpDtl1 = GetAllGroups(Nodes); //grpDtl.GetRange(0, grpDtl.Count);
//bind two grid with all groups name
if (_grpDtl != null && _grpDtl.Count > 0)
{
dgSingleGroups.AutoGenerateColumns = false;
dgSingleGroups.DataSource = grpDtl;
dgSingleGroups.Columns[0].DataPropertyName = "Select";
dgSingleGroups.Columns[1].DataPropertyName = "GroupName";
dgSingleGroups.Columns[1].ReadOnly = true;
dgSingleGroups.Columns[0].Width = 47;
dgSingleGroups.Columns[1].Width = 346;
dgAllGroups.AutoGenerateColumns = false;
dgAllGroups.DataSource = grpDtl1;
dgAllGroups.Columns[0].DataPropertyName = "Select";
dgAllGroups.Columns[1].DataPropertyName = "GroupName";
dgAllGroups.Columns[1].ReadOnly = true;
dgAllGroups.Columns[0].Width = 47;
dgAllGroups.Columns[1].Width = 346;
}
grpDtl1 = null;
grpDtl = null;
_grpDtl = null;
GetAllGroups() iterate in treeview node collection and accumulate node name.
private List<AllGroupNames> GetAllGroups(TreeNodeCollection tnCollection)
{
//accumulate group name in recursive fashion
foreach (TreeNode tn in tnCollection)
{
if (tn.Tag != null)
{
if (((object)tn.Tag).GetType().ToString().Contains("TunerDetails"))
{
_grpDtl.Add(new AllGroupNames { Select = false, GroupName = tn.Text });
}
GetAllGroups(tn.Nodes);
}
}
return _grpDtl;
}
Now problem is when i check second grid checkbox then my first grid checkbox is getting checked invisibly means when i am reading first grid's first column value in loop then i am getting checkbox value true. where as i have not checked my first grid's any checkbox.
when i select any row of second grid that same row is getting automatically selected in first grid.
I just select one row from right side grid and same row of left side grid automatically gets selected....which is problem for me. Why two grid syncing automatically. screen shot attached.
why it is happening i am not able to capture the reason. please help me what to change in code to get rid of this problem.
Apparently every object of class AllGroupName has a Boolean property Select.
You created Column[0] such, that the checkbox is checked whenever this boolean is true, and vice versa: whenever the operator checks this checkbox, the corresponding AllGroupName.Select will become true.
You decided to use the same DataSource as object in two DataGridViews.
Operator checks the checkbox of row[4] in Dgv1
This means that DataSource[4].Select = true;
This means that all objects that have this DataSource will be notified that [4] has changed
Row[4] in Dgv1 and Dgv2 will be updated: checkbox is checked.
If you don't want that changes in Dgv1 are refelected in Dgv2, then you should make a copy of the datasource.
List<...> data1 = ...; // shouldn't this be an BindingList<...> ?
Dgv1.DataSource = data1;
List<...> data2 = new List<...>(data1); // clone data1
Dgv2.DataSource = data2;

Why is DataView readonly despite "AllowEdit=true"?

I have code (below) that I think should allow me to update the underlying tables, but I continue to get a "Underlying data is read only" error.
In the code below, everything I've tried is included. Clearly, I'm missing something! A search in SO hasn't found clues...
APT.Columns["Selected"].ReadOnly = false;
TWR.Columns["Selected"].ReadOnly = false;
RWY.Columns["Selected"].ReadOnly = false;
APT.Columns["Selected"].Expression = "false";
TWR.Columns["Selected"].Expression = "false";
RWY.Columns["Selected"].Expression = "false";
// DataView with filtered "parent" table data
// Apply user's filter for the "Fix"
DataView dataView = new DataView(APT)
{
RowFilter = FixFilter(chkboxShowAll.Checked),
Sort = "FacilityID",
AllowEdit = true,
};
// RWY and TWR dont have ARTCC (filter item),
// so we can't filter by that,
// and "Join" makes the table readonly,
//so must grab root ID and change manually
DataView dvTWR = new DataView(TWR)
{
AllowEdit = true // Enable editing
};
DataView dvRWY = new DataView(RWY)
{
AllowEdit = true
};
// TWRs and RWYs have the same ID as the APT,
// but not may have a TWY or RWY (e.g., Seabase)
// This should update the "Selected" boolean
foreach (DataRowView dataRowView in dataView)
{
dataRowView.BeginEdit();
dataRowView["Selected"] = true; // *** <- EXCEPTION HERE
dataRowView.EndEdit();
int result = dvRWY.Find(dataRowView["ID"]);
if (result != -1)
{
dvRWY[result].BeginEdit();
dvRWY[result]["Selected"] = true;
dvRWY[result].EndEdit();
}
result = dvTWR.Find(dataRowView["ID"]);
if (result != -1)
{
dvTWR[result].BeginEdit();
dvTWR[result]["Selected"] = true;
dvTWR[result].EndEdit();
}
}
dvTWR.Dispose(); // Commit/close tables
dvRWY.Dispose();
At the annotated code line, the exception fires:
System.Data.ReadOnlyException: 'Column 'Selected' is read only.'
Can anyone tell me the error of my ways?
Dai is correct: A dataview cannot modify static public in-memory tables. However, a datagridview, bound directly to the datatable, can.
This is a better solution for me, as ultimately I need to display the "selected" rows: I created a datagridview for each table and placed each one in a tab control container. I checked the "Can edit" box for each datagridview in designer.
One can then drilldown to modify each column's readonly property within designer, but I found it easier to assign the readonly property after I read data into datatables from the text files (either one works, and one can change the designer-setting programmatically as they are actually the same property).
Looping the "Selected" column rows true or false is conveniently dependent on the filter applied to the datagridview, making a single calling routine efficient (just do or do not apply a filter to the datagridview(s) and pass the dgv and/or columns to the called routine).
As a plus, users can un/check "Selected" rows. The underlying table is changed! The tables can then be efficiently filtered on "Selected" for other events/output.
// schema built in VS designer...
static public DataTable APT = new SCTData.APTDataTable();
// Table populated from FAA fixed-column text files (cols vary by file)
ReadFixes.FillAPT();
// Assign the table to the datagridview, apply filter and sort
DgvArpt.DataSource = APT;
(DgvArpt.DataSource as DataTable).DefaultView.RowFilter = filter;
AdjustColumnOrderNSort(DgvArpt);
// Loop the filtered datagrid to make "Selected" col = true
UpdateSelected(DgvArpt,true);
private void UpdateSelected (DataGridView dgv, bool hasFilter = false)
{
// If the filter is applied, selected boxes are true
// otherwise, ALL the selected boxes are false
// But if the ShowAll box is checked, ignore the update
if (chkboxShowAll.Checked == false)
{
foreach (DataGridViewRow row in dgv.Rows)
{
row.Cells["Selected"].Value = hasFilter;
}
}
}

Bind and Highlight Specific DataGridView Row

I am binding data from excel file in a list on button click and this works perfectly. Finally the data is binded to a DataGridView. Now I want to iterate the list to check if there are any data that isn't included to the database after binding to a DataGridView. If any data mismatches, then it should highlight the specific row with red color in the DataGridView. Note: There could be multiple data that will not match. Something as the below image and the code tried:
grdUpload.Rows.Clear();
for (int i = 0; i < lstData.Count; i++) //lstData - The Data List
{
if (Facede.ExcelUpload.CheckIfExists(lstData)) //Checking if any data mismatches
{
grdUpload.DataSource = lstData;
grdUpload.Rows[i].DefaultCellStyle.BackColor = Color.Red; //Highlight the row data that mismatches
}
else
{
grdUpload.DataSource = lstData;
}
}
public bool CheckIfExists(List<Data> lst)
{
bool flag = false;
foreach (Data d in lst)
{
string Query = "SELECT M.EmpNo FROM Data m WHERE M.EmpNo = '" + d.EmpNo + "'";
DataTable dt = SelectData(Query);
if (dt != null && dt.Rows.Count > 0)
{
flag = true;
}
else
{
flag = false;
}
}
return flag;
}
Now the issue is it doesn't highlight the specific row if data like EmpNo mismatches. Anything that I am missing here?
Problem is in your for loop.
You are firstly binding data to your datagridview.
Then you are entering for loop
Inside it you ask if condition is met and if it is you AGAIN bind same data to datagridview but after it you color it.
For loop continues and it again enters part where it meets condition and AGAIN you BIND same data but now you overwrite colored data with new (but same) data and then color some new row.
So what you need to do is
Load data into datagridview
Loop through datagridviewrows and if meet condition color that row
So code should look like this:
//Here you bind your data to datagridview
//In code bellow if you want to get row's column's data use
//row.Cells["CELL_VALUE"].Value (convert to what datatype you need before comparing)
foreach (DataGridViewRow row in dataGridView1.Rows)
{
if (condition)))
{
dataGridView1.Rows[row.Index].DefaultCellStyle.BackColor = Color.Red;
}
}

Remember the check-box option in a GridView while paging and looping through entire GridView

I have a gridview on a aspx page with pagination enabled. this gridview contains some data fields from a database and a check-box for each row.
Now, I read on this post: loop all gridview rows on button click when paging enabled that to be able to loop through all the rows on all the pages of the gridview, I have to disable the pagination, rebind the gridview, loop through all rows, re-enable the pagination and finally rebind the gridview.
I started out wondering whether the check-box option will be remembered if I rebind the datasource before looping through all the rows, but quickly determined that even going from one page to the next page then back again the check-box option is lost.
I need to have a gridview with pagination and a check-box on each row, then loop through the entire gridview on the click of a button and do some action depending on the check-box option.
Its not possible with the GridView natively. But there are many methods to simulate the same behaviour. One method will be to handle the issue on the PageIndexChanging event like this.
protected void OriginalTable_PageIndexChanging(object sender, GridViewPageEventArgs e)
{
var selectedIDs = (Session["CheckedIDs"] != null) ?
Session["CheckedIDs"] as List<int> : new List<int>();
//we are now at current page. set the checked ids to a list
foreach (GridViewRow row in OriginalTable.Rows)
{
//get the checkbox in the row ( "HasEmail" is the name of the asp:CheckBox )
var emailCheckBox = row.FindControl("HasEmail") as CheckBox;
//gets the primary key of the corresponding row
var rowOrgID = Convert.ToInt32(OriginalTable.DataKeys[row.RowIndex].Value);
//is row org_id in the selectedIDs list
var isRowIDPresentInList = selectedIDs.Contains(rowOrgID);
// add to list
if (emailCheckBox.Checked && !isRowIDPresentInList)
{
selectedIDs.Add(rowOrgID);
}
//remove from list
if (!emailCheckBox.Checked && isRowIDPresentInList)
{
selectedIDs.Remove(rowOrgID);
}
}
OriginalTable.PageIndex = e.NewPageIndex;
BindTable();
//we are now at the new page after paging
//get the select ids and make the gridview checkbox checked accordingly
foreach (GridViewRow row in OriginalTable.Rows)
{
var emailCheckBox = row.FindControl("HasEmail") as CheckBox;
var rowOrgID = Convert.ToInt32(OriginalTable.DataKeys[row.RowIndex].Value);
if (selectedIDs.Contains(rowOrgID))
{
emailCheckBox.Checked = true;
}
}
Session["CheckedIDs"] = (selectedIDs.Count > 0) ? selectedIDs : null;
}
Here we are using Session to maintain the values across pages. As an added advantage you will get the checked values in any other event by accessing the session variable.
Update
If you already have pre-populated HasEmail field, do this to set the values at initialization
private void BindTable()
{
DataTable table = GetTableFromDatabase();
var selectedIDs = table.AsEnumerable()
.Where(r => r.Field<bool>("HasEmail"))
.Select(r => r.Field<int>("ORG_ID"))
.ToList();
if (selectedIDs != null && selectedIDs.Count > 0)
Session["CheckedIDs"] = selectedIDs;
OriginalTable.DataSource = table;
OriginalTable.DataBind();
}

Categories

Resources