ASPxGridView on update can't find row cell template control - c#

I have the following code:
protected void gv_AfterPerformCallback(object sender, ASPxGridViewAfterPerformCallbackEventArgs e)
{
if(e.CallbackName == "UPDATEEDIT")
{
ASPxGridView gv = (ASPxGridView)sender;
GridViewDataColumn col = gv.Columns[0] as GridViewDataColumn;
ASPxTextBox txt = gv.FindEditRowCellTemplateControl(col, "test") as ASPxTextBox;
}
}
In this code, gv is defined and it finds col. However, when running the FindEditRowCellTemplateControl part, it returns null for the textbox. The textbox definitely exists, I know this as this code used to work and hasn't been touched, but also if I change the if statement to look for e.CallbackName == "CANCELEDIT", the code works as intended. There are other calls to other controls within this same block and none of them are returning valid controls.
The only thing that has changed between working code and not working, is that I changed the BackColor of another control in another column in the same grid. I have since changed it back as I wondered if this, inexplicably, was the issue.
What can have happened? Why would txt be null when e.CallbackName == "UPDATEEDIT" but is initialised correctly when e.CallbackName == "CANCELEDIT"?

Related

Synfusion WinForms GridDataBoundGrid: What events are they for detecting header clicks

I recently installed syncfusion(Previously using telerik) and am trying to switch out the the RadGridView for the GridDataBoundGrid and my function doesnt seem to work the same as it did
private void OnColumnHeaderMouseClick(object sender, ColumnClickEventHandler e) {
if (e.Row is GridViewTableHeaderRowInfo) {
int index = tabControl1.SelectedIndex;
EditHeader eh = new EditHeader(this.UpdateHeader);
eh.TextBox1.Text = ds.Tables[index.ToString()].Columns[e.ColumnIndex].ToString();
eh.TextBox2.Text = e.ColumnIndex.ToString();
eh.Show();
}
}
e.Row Doesnt exist GridViewTableHeaderRowInfo Doesnt exist and e.ColumnIndex Doesnt exist
The point of this is to open another part of the application when a column header is clicked and im not sure if im gonna have to rewrite the function from scratch or not.
So are there any events that would work directly with my function or do I have to write a workaround
By default, the CellClick event will trigger while the clicking on table cells. The CellType property can be used to check whether the CurrentCell is column header cell or not and the ColIndex property can be used to get the current column index. Please make use of code and sample,
Code snippet
//Event Triggering
this.gridDataBoundGrid1.CellClick += GridDataBoundGrid1_CellClick;
//Event handling
private void GridDataBoundGrid1_CellClick(object sender, GridCellClickEventArgs e)
{
//To Check for column header cell
if(this.gridDataBoundGrid1[e.RowIndex, e.ColIndex].CellType == "ColumnHeaderCell")
{
//Your code show the another part of the project.
}
}
Note
Please make use of below KB to get the particular record/row based on index.
KB link: https://www.syncfusion.com/kb/5953/how-to-get-the-row-data-from-griddataboundgrid
Sample link: https://drive.google.com/file/d/0Bwk9nUFE3rlxR0xZMXRhU0xqdTA/view?usp=sharing
Regards,
Arulpriya

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

All rows selected on clicked

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());
}
}

SqlDatasource process records before display

I have a database with link urls and their respective display texts. I need to check if they are broken or not before their display string is shown in the gridview.
I am using SqlDatasource, is there a way to process records and use custom HTML markup to show them while using the SqlDataSource?
I am trying to use the OnSelected event of SqlDatasource but cant get how to use it.
I believe what you are trying to do is make sure that the hyperlink is valid before it gets put into the datagrid. To do this, you would need to subscribe to the RowDataBound event on your grid. From there, you can run code to evaluate your URL. Here is a quick example that would check to be sure that the URL field is not an empty string:
protected void selectedBookList_RowDataBound(object sender, GridViewRowEventArgs e)
{
if ((e.Row != null) && (e.Row.RowType == DataControlRowType.DataRow))
{
string test = DataBinder.Eval(e.Row.DataItem, "URL").ToString();
if (test.Length == 0)
{
e.Row.Cells[3].Visible = false;
}
else
{
e.Row.Cells[3].Visible = true;
}
}
}
Instead of testing to be sure the length is equal to zero, you could check to see if the link is dead or not. Once you have evaluated it, you can hide the cell like I am doing here or you could modify the link, put in a generic link, etc.

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