All rows selected on clicked - c#

I'm building a application in C# Winforms and using a Datagridview.
My problem is that when I click on a row, all rows are selected (without intention) and the application crashes (as the values inserted from the grid view selected row into labels are not intact (too many values...).
The correct behavior I'm looking for is the selection of on row only.
I thought the problem might be in the selectionMode (I used the value "RowHeaderSelect"), but I changed it, and the problem persisted, so it isn't it.
Do you have an idea what might be the problem ??
Not relying on much code, really, but here it is:
private void dgvCustomersList_MouseClick(object sender, MouseEventArgs e)
{
{
customerFunctions ChoosenRow = new customerFunctions(); //empty
DataGridViewRow dr = dgvCustomersList.SelectedRows[0];
ChoosenRow.CfirstName = dr.Cells[1].Value.ToString();
ChoosenRow.ClastName = dr.Cells[2].Value.ToString();
ChoosenRow.Caddress = dr.Cells[3].Value.ToString();
ChoosenRow.CcreditNumber = int.Parse(dr.Cells[7].Value.ToString());
ChoosenRow.CpersonalID = int.Parse(dr.Cells[5].Value.ToString());
}
}

Related

Datagridview winforms cells doesnt get updated unless focus back on the grid

I am working with winforms c# datagridview and ran into a bug that I m not sure how to resolve. I have a datagridview in which the datasource is a datatable. The datagridview contains editable text fields and cellvaluechanged event as well as button column which I respond to thru a cellclick event. Currently when I change the value in a cell , hit the enter key to leave the just updated cell and click the button. The cellclick event which acts as the button click runs a task (TPL) in which the continuewith of the tasks updates values in the datagridview and that works because all the values that needed to be changed gets changed. The issue is that when I change a text value and don't hit the enter key and just immediately click the button on the row. the ui doesn't get updated intill I click on the cells to see the new values. I have looked this up and found that if I set the
datagridview.Currentcell = datagridview.Rows[e.RowIndex].Cells[4]
to the cells that I want to see the new values to. The new values appear. I don't want run for each cell I was wondering if there is a better way in handling this issue?
This is the code:
private void dgv_CellClick(object sender, DataGridViewCellEventArgs e)
{
//Button on grid
if (e.ColumnIndex == 17)
{
string val1 = dgv.Rows[e.RowIndex].Cells[3].Value.ToString();
string val2 = dgv.Rows[e.RowIndex].Cells[5].Value.ToString();
Task.Factory.StartNew<Dictionary<string, Response>>(() => GenerateData(val1, val2)).ContinueWith(ant => {
int rowId = Convert.ToInt32(this.dgv.Rows[e.RowIndex].Cells[1].Value);
SetResponse(rowId, this.DataSet.DataTable, ant.Result);
// i have tried the code below and it fixes the issue but don't want to go this route
//for (int i = 5; i < 12; i++) dgv.CurrentCell = dgv.Rows[e.RowIndex].Cells[i];
}, TaskScheduler.FromCurrentSynchronizationContext());
}
}
}
private void dgv_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 5)
{
string val1 = this.dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString().Trim();
if (!string.IsNullOrEmpty(val1))
{
//dgv.BeginEdit(false);
this.dgv.Rows[e.RowIndex].Cells[6].Value = DBNull.Value;
//dgv.EndEdit(DataGridViewDataErrorContexts.Commit);
}
}
}
By adding these two lines of code resolved the issue
this.dgv.EndEdit();
this.dgv.CurrentCell = null;

ASP.NET How do I check ever row in the gridview?

I want to add value into a Grid view via dropdownlist with a button.
I want the ddTN.SelectedItem.value in the Grid view to be unique. No duplication
How do I check every row for the ddTN.SelectedItem.value before adding a new ddTN.SelectedItem.value into the Grid view?
This are the codes that I have and it keep comparing the value with the first value in the gridview. Not the others.
I don't want to use a checkbox and such. All the example I found required using checkbox.
protected void Insert(object sender, EventArgs e)
{
int i = 0;
var p = 1;
DataControlFieldCell cell = GridView1.Rows[i].Cells[p] as DataControlFieldCell;
if (cell.Text != ddTN.SelectedItem.Value)
{
dt.Rows.Add(ddTN.SelectedValue, ddDuration.SelectedValue);
ViewState["Customers"] = dt;
this.BindGrid();
label.Text = "";
p++;
}
else
{
label.Text = "Exercise already inserted";
}
}
It looks like you were intending on looping over the items in the grid but you have forgotten the looping mechanism. In your code, it always only checks the first item because i is initialized to 0 and never changes.
Try using a looping mechanism like a for loop or a while loop. Or, if you know the items in the grid from the beginning, perhaps use a hash table for quickly checking if the selected item already exists.
Keep trying, you are almost there!

Automatic validation in a DataGridView

I'm not new to WinForms but I have always "rolled my own" when it comes to validation - and I think it's time to take advantage of the built-in stuff. I Googled around for some basics but I'm not finding what I need...
I've got a DataGridView. I have a (custom) object that has four String properties. I am getting a List<> of them from an XML file.
So when I do this:
dgv.DataSource = genericListOfStationObjects;
the rows do show up correctly in the DataGridView. So the databinding is working just fine - at least in the "incoming" direction.That's good.But what I need to do is:
track IsDirty on each row (without manually adding a flag?)
visually indicate (within the DataGridView) if any of the values in the DataGridView's cells are invalid. (I have validation methods on my custom object (of which the List<> is comprised.) I cannot get those "error glyphs" to show up. I've tried all the SO posts I could find on that...
Thank you very much,Eliezer
To answer your first question there are two native properties that you will want to utilize:
IsCurrentCellDirty
IsCurrentRowDirty
These only work for the currently selected cell/row. So you may have to resort to making your own if you need to track "IsDirty" on each row. But there is an event that comes with the native dirty settings, CurrentCellDirtyStateChanged you can utilize to log all of the changes. You could also use CellValueChanged to log any changes you might need. I personally use a form-level property to keep track if I have any data edits/changes by using either of these events and if I do, I save the edits before closing the form.
Data validation is fairly straightforward on the WinForms DataGridView. To get the red error glyphs to show simply set the ErrorText of a cell or row. I also utilize the DataGridView's native RowValidating event as well.
void dg_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
{
DataGridViewRow dgRow = dg.Rows[e.RowIndex];
if ((dgRow.Cells["yourColumnName"].Value == null) ||
(dgRow.Cells["yourColumnName"].Value.ToString().Length == 0))
{
// Set both the row and cell error text at the same time.
dgRow.ErrorText = dgRow.Cells["dgTxtColTest List"].ErrorText =
"You must enter a value in the " + yourColumnName + " column."
e.Cancel = true;
}
}
When the row is validated you must clear any error messages you might have created above:
void dg_RowValidated(object sender, DataGridViewCellEventArgs e)
{
// Clear errors from row header and cells in the row
DataGridViewRow row = dg.Rows[e.RowIndex];
row.ErrorText = ""; // Clear the row header error text
// Clear all error texts from the row
foreach (DataGridViewCell cell in row.Cells)
{
cell.ErrorText = ""; // Clear each cell in the row as now row is valid
}
}

when I want to change a ComboBox of datagridview, its automatically change all other combos of same DataGridView

First of all, I must mention that I have seen this question, but it didn't help me to fix my problem.
According to my previous question, I saved my DataGridView to an XML file. Now I am going to fill the DataGridView when I load the window form using the data stored on the XML file.
My problem is that when I want to set the value of one ComboBox based on the stored data, the other ComboBox's value changes too. I want to set each ComboBox's value separately.
My code is as follows :
private void WindowSelection_Load(object sender, EventArgs e)
{
dataGridSource = DeserializeFromXML();
foreach (WindowHolder obj in dataGridSource)
{
int index = dataGridViewWindowSelection.Rows.Add();
DataGridViewComboBoxColumn combo2 = new DataGridViewComboBoxColumn();
combo2 = (DataGridViewComboBoxColumn)dataGridViewWindowSelection.Rows[index].Cells["Reader"].OwningColumn;
combo2.DataSource = readerSource;
int readerSourceIndex = findReaderSourceIndex(obj.reader);
if (readerSourceIndex != -1)
{
combo2.DefaultCellStyle.NullValue = readerSource[readerSourceIndex];
}
else
{
combo2.DefaultCellStyle.NullValue = readerSource[0];
}
dataGridViewWindowSelection.Rows[index].Cells["Location"].Value = obj.location;
dataGridViewWindowSelection.Rows[index].Cells["AlwaysOnTop"].Value = obj.alwaysOnTop;
dataGridViewWindowSelection.Rows[index].Cells["AlwaysShow"].Value = obj.alwaysShow;
}
}
Do you mean the line where you're changing combo2.DefaultCellStyle?
This happens because combo2.DefaultCellStyle is a reference to the default cell style of all the combos, so you're not changing this one combo - you're changing the common default style.
If you want the style of this combo to be different from the default one (and from the other combos' style), you should probably create a separate style and set it as the style of combo2.
I guess the statement should look something like combo2.DefaultCellStyle = ... or combo2.SetDefaultCellStyle( ... )

DataGridView throwing "InvalidOperationException: Operation is not valid..." when adding a row

I want an OpenFileDialog to come up when a user clicks on a cell, then display the result in the cell.
It all works, except that the DataGridView displays an extra row, for adding values to the list it's bound to. The row shows up if dataGridView.AllowUserToAddNewRows == true, which is what I want. What I don't want is for the application to crash when that row is edited programatically; instead, it should do exactly what it would do if the user had edited that row manually (add the new row to the underlying list, push another empty row onto the grid for adding values).
I read about SendKeys.Send(), which should make the DataGridView behave exactly as though the user had typed the value in; however, it does not work either. Here is what I am trying:
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
dataGridView1.CurrentCell = cell;
//simply doing a cell.Value = etc. will cause the program to crash
cell.ReadOnly = false;
dataGridView1.Columns[cell.ColumnIndex].ReadOnly = false;
dataGridView1.EditMode = DataGridViewEditMode.EditOnEnter;
dataGridView1.BeginEdit(true);
SendKeys.Send(openFileDialog1.FileName + "{Enter}");
dataGridView1.EndEdit();
cell.ReadOnly = true;
dataGridView1.Columns[cell.ColumnIndex].ReadOnly = true;
}
//I would expect the FileName would be in the cell now, and a new empty
//row tacked onto the end of the DataGridView, but it's not; the DataGridView
//is not changed at all.
I found a workaround on this page, though I don't know why it works
public MyForm()
{
InitializeComponent();
//Create a BindingSource, set its DataSource to my list,
//set the DataGrid's DataSource to the BindindingSource...
_bindingSource.AddingNew += OnAddingNewToBindingSource;
}
private void OnAddingNewToBindingSource(object sender, AddingNewEventArgs e)
{
if(dataGridView1.Rows.Count == _bindingSource.Count)
{
_bindingSource.RemoveAt(_bindingSource.Count - 1);
}
}
I'm getting very sick of spending so much time dealing with Visual Studio bugs...
I was having the same problem when trying to programattically edit cells with a binding source.
""Operation is not valid due to the current state of the object"
Which operation? What State? So helpful.
My code seem to work fine except when editing the last row in the grid.
Turns out the key is DataGridView.NotifiyCurrentCelldirty(true)
The correct sequence for programatically editing a cell, so it works the same as if the user did it.
(A new empty row appears when changing a cell in the last row) is something like this:
1) Make the cell to edit the current cell (do what ever you need to the current currentcell, first
like calling endEdit if it is in edit mode.)
2) Call DataGridview.BeginEdit(false)
3) Call DataGridView.NotifyCurrentCellDirty(true)
4) Modify the value.
5) Call DataGridView.EndEdit()
And you'll want to do something for the RowValidating and RowValidated events.
One of my routines for updating a cell value looks like this:
This is from a method in my class derived from DataGridView.
You could do the same thing from the containing form, calling
through a DataGridView instance, because the methods are public.
Here the calls are using an impliciit 'this.'
private void EnterTime()
{
if (CurrentRow == null) return;
SaveCurrentCell(); // Calls EndEdit() if CurrentCell.IsInEditMode
DataGridViewCell previous = CurrentCell;
CurrentCell = CurrentRow.Cells[CatchForm.TimeColumn];
BeginEdit(false);
NotifyCurrentCellDirty(true);
CurrentCell.Value = DateTime.Now;
EndEdit();
CurrentCell = previous;
}
I’m not sure why a separate call is needed.
Why doesn’t BeginEdit, or actually modifying the cell value, cause the right
things to happen?
And if you move the NotifyCurrentCellDirty call to after you actually modify the cell,
it doesn’t behave correctly either. All very annoying.
This is old, but I am running VS2010 and just come across this issue. I have a DataGridView bound to a List<T> using a BindingList<T>. I have a drag n' drop event on my DataGridView and it would throw this exception after deleting all rows from the DGV (except for the last blank one which one cannot delete) and then adding new rows to the DGV in the DragDrop handler via the BindingList<T>. This exception was not thrown if I simply added rows manually editing individual cells.
One solution I read said to handle the BindingList<T>.AddNew event, but I found that this event did not fire when calling BindingList<T>.Add() within the DragDrop event handler (I'm not sure why). I solved the issue by adding
if(bindingList.Count == 0)
bindingList.RemoveAt(0)
inside of the DragDrop event handler before adding new objects to bindingList. It seemed that adding an object to the bindingList failed when the only "object" in the bindingList was the one associated to the final blank row. The point of a BindingList<T> is to allow the developer to work with it instead of the DGV directly, but it seems doing so can cause problems in border cases.
The relationship between DGV rows and BindingList<T> rows seems to be a bit of a gray area. I have not spent much time investigating this, but it is not clear to me what is the state of the "object" in the BindingList<T> associated to the final (empty) row of the DGV. However, it does seem like the "object" at the end is only instantiated "correctly" when you interact with the final row directly (not via a DataSource).
Try this:
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
int row = e.RowIndex;
int clmn = e.ColumnIndex;
if(e.RowIndex == dataGridView1.Rows.Count- 1)
dataGridView1.Rows.Add();
dataGridView1.Rows[row].Cells[clmn].Value = openFileDialog1.FileName;
}
EDIT
I didn't notice that you are binding your datagridview :(
Ok, to solve it: use binding source, set its DataSource property to your list, then set the data source of the data grid view to this binding source. Now, the code should look like so:
public partial class frmTestDataGridView : Form
{
BindingSource bindingSource1 = new BindingSource();
List<string> datasource = new List<string>();
public frmTestDataGridView()
{
InitializeComponent();
datasource.Add("item1");
datasource.Add("item2");
datasource.Add("item3");
bindingSource1.DataSource = datasource;
dataGridView1.DataSource = bindingSource1;
}
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
int row = e.RowIndex;
int clmn = e.ColumnIndex;
if (e.RowIndex == dataGridView1.Rows.Count - 1)
{
bindingSource1.Add("");
}
dataGridView1.Rows[row].Cells[clmn].Value = openFileDialog1.FileName;
}
}
}
Remember to use Row.BeginEdit() and Row.EndEdit() if you get this error while editing a value in a row, using DataGrid or GridEX from Janus (in my case). The sample code that Darrel Lee posted here (https://stackoverflow.com/a/9143590/1278771) remind me to use these instructions that I forgot to use and this solved the problem for me.

Categories