Is there any possibility to skip or delete specific column of DataGridView from updating to the database?
I need to prevent column from updating to the database, because the column values is encrypted and when I decrypt, the decrypted values updated to the database.
I used this code before, but this really slows the grid.
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (hide == false && e.ColumnIndex == 2 && e.RowIndex != this.dataGridView1.NewRowIndex)
{
e.Value = Decrypt(e.Value.ToString());
}
}
Updating values with this code:
private void dataGridView1_RowValidated(object sender, DataGridViewCellEventArgs e)
{
DataTable changes = ((DataTable)dataGridView1.DataSource).GetChanges();
if (changes != null)
{
MySqlCommandBuilder mcb = new MySqlCommandBuilder(mySqlDataAdapter);
((DataTable)dataGridView1.DataSource).AcceptChanges();
mySqlDataAdapter.UpdateCommand = mcb.GetUpdateCommand();
mySqlDataAdapter.Update(changes);
}
}
Based on what the title is saying, it's enough to set ReadOnly property of the column to true, but since you want to show decrypted value of the column in your grid, to prevent the column from being updated in database, you can use either of these options:
Show encrypted value in the column itself and change your update command to not contain statement for updating that specific column.
You can show the encrypted value in another unbound column.
In this post I show you an example of the second solution.
I suppose you have a string Decrypt(string value) method which decrypts an encrypted string. Also I can you have a column "A" which contains encrypted value and as the question you want to show decrypted value in a "B" column in grid.
So perform these steps:
Set Visible property of "A" column to false.
Add a DataGridViewTextBox column and set its name to "B"
Handle CellFormatting event of DtaGridView like below:
private void grid_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if(e.ColumnIndex<0 || e.RowIndex<0)
return;
var columnB = grid.Columns[e.ColumnIndex];
if (columnB.Name != "B")
return;
var value = grid.Rows[e.RowIndex].Cells["A"].Value;
if (value == null || value == DBNull.Value)
return;
cell.Value = Decrypt(value.ToString());
}
Note
It's not good idea to save changes on after you leave row. It's better to save changes after the edit is finished by click on a Save button.
You don't need to call AcceptChanges. In fact you should not!
Usually its enough to set cell.Value = Decrypt(value.ToString());but since you may have performance issues by Decrypt, Instead of setting e.Value you can check if the cell doesn't have value, will set the value for cell:
var cell = grid.Rows[e.RowIndex].Cells["B"];
if (cell.Value== null || cell.Value == DBNull.Value)
{
cell.Value = Decrypt(value.ToString());
}
Please pay attention to the warning which is in
remarks section of the CellFormatting event: CellFormatting event occurs every time each cell is painted, so
you should avoid lengthy processing when handling this event.
Related
I am having a grid which shows list of products with following columns :
ProductId,ProductName,MRP,FinalAmount
Now I have kept MRP as editable so that user can change it based on discount on some products.I have kept validation on MRP column to not allow user to enter null value but the problem is when I raised the validation message original MRP value is LOST.
So what I am trying to do is when user enter negative/null value then I want to show message and retain last MRP value.
Code :
private void grdProductList_CellEndEdit_1(object sender, DataGridViewCellEventArgs e)
{
if (grdProductList.CurrentCell == null ||
grdProductList.CurrentCell.Value == null ||
e.RowIndex == -1) return;
if (grdProductList.CurrentCell.ColumnIndex.Equals(3))//MRP
{
if(string.IsNullOrEmpty(grdProductList.Rows[grdProductList.CurrentRow.Index].Cells["MRP"].Value.ToString()))
{
MessageBox.Show("MRP cannot be empty.Please provide value", "Error");
return;
}
decimal.TryParse(grdProductList.Rows[grdProductList.CurrentRow.Index].Cells["MRP"].Value.ToString(), out decimal mrp);
if(mrp < 0)
{
MessageBox.Show("MRP cannot have negative value", "Error");
return;
}
grdProductList.Rows[grdProductList.CurrentRow.Index].Cells["FinalAmount"].Value = mrp;
//calculation code based on mrp
}
}
I have found that DataGridView provides a method called CancelEdit which discards the changes and also helps to retain original value.
I just need to call this method like below and got the expected behaviour :
if(string.IsNullOrEmpty(grdProductList.Rows[grdProductList.CurrentRow.Index].Cells["MRP"].Value.ToString()))
{
MessageBox.Show("MRP cannot be empty.Please provide value", "Error");
grdProductList.CancelEdit();
return;
}
Store the MRP original value in a temp variable,
if user entered null or negative value, restore the temp value to current grid cell
I have an employees table in which first number is set as not null and second number that can be **null* so when I call the employees information to view their information in DataGridView the null values appear as empty cells but I want to show "Unavailable" word instead of the empty cell , so how can I do this?
You can use either of these options:
Set NullValue property of DefaultCellStyle of the column. It sets the cell display value corresponding to a cell value of DBNull.Value or null.
Use CellFormatting event and set e.Value when the value of cell is DBNull.Value or null
Example 1
this.dataGridView1.Columns[1].DefaultCellStyle.NullValue = "Unavailable";
Example 2
void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (e.ColumnIndex < 0 || e.RowIndex < 0)
return;
if (e.Value == DBNull.Value || e.Vallue == null)
e.Value = "Unavailable";
}
Change your Select statement to something like this (use CASE WHEN):
SELECT Id, CASE WHEN SecondNumber IS NULL THEN 'Unavailable' ELSE SecondNumber END AS SecondNumber
FROM yourTable
This solution would also include an extension method so please make the following extension method.
this is what we will need to set the values of the grid in a more clean way (optional though)
public static void ApplyAction<T>(this IEnumerable<T> source, Action<T> action)
{
foreach (var entity in source)
{
action(entity);
}
}
now all you have to do is going to be the following :
dataGridView1.Rows.OfType<DataGridViewRow>().Where(c => c.Cells[ColumnName.Index].Value == null).ApplyAction(new Action<DataGridViewRow>(c => c.Cells[ColumnName.Index].Value = "Unavailable"));
Knowing the name of the column to be queried, how can I extract the value from that column for the currently selected record in a DataGridView?
IOW, if I have a DataGridView with columns named id, Date, Time, Space, and I want the value of the Space column for the currently selected row, how can I assign that value to a String variable?
In pseudocode, I would expect it to be something like:
String s = dataGridView1.CurrentRow["Space"].ToString();
...but I'm sure it's not really that straightforward.
UPDATE
The answers look good, but is there a way to get the value from the current row that doesn't respond to a dataGridView event? I need to assign the value apart from the dataGridView being clicked or any other event. IOW: is there a way to get the current row?
You can use
dataGridView1.CurrentRow.Cells[yourColumn]
to access the current row if there is one..
..and even if you have MultiSelect on, you can always use
dataGridView1.SelectedRows[0].Cells[yourColumn]
to access the first selected row..
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value != null)
{
string s = dataGridView1.Rows[e.RowIndex].Cells["Space"].Value.ToString();
}
}
In the Grid_RowDataBound event
protected void Grid_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.DataItem == null)
return;
DataRowView row = e.Row.DataItem as DataRowView;
if(row["Space"] != null)
{
string s = row["Space"].ToString();
//do stuff
}
}
I reckon this will work:
private string GetCurrentOrFirstValOfColumn(string colName)
{
String colVal = String.Empty;
DataGridViewRow dgvr = dataGridViewFileContents.CurrentRow;
if (null != dgvr.Cells[colName].Value)
{
colVal = dgvr.Cells[colName].Value.ToString();
}
return colVal;
}
I have this unbound column :
bandedGridColumn.UnboundType = DevExpress.Data.UnboundColumnType.String;
bandedGridColumn.OptionsColumn.AllowEdit = false;
And i'm assigning value for this column in CustomUnboundColumnData :
private void vwVD_CustomUnboundColumnData(object sender, CustomColumnDataEventArgs e)
{
if (e.Column.FieldName == "UnitOfMeasureName" && e.IsGetData)
{
e.Value = UnitOfMeasureName;
vwVD.RefreshData();
}
}
The problem is the Column does not display data simultaneously, i have to click to the column's cell to make it display value correctly, any idea how to fix this ?
You should remove the vwVD.RefreshData() method call from the CustomUnboundColumnData event handler. This method should not be called here. Also, please make certain that the column's FieldName property is set a unique value between other columns and there is no column with such field name in the DataSource.
I suppose the following example on devexpress forum would be helpful to you:
http://www.devexpress.com/Support/Center/Example/Details/E2442
I have a DataTable filled with information about audio tracks. DataTableColumn that stores the track number is of a UInt32 type so when I display the DataTable in DataGridView, I'm able to sort data by that column. For tracks when there is no track number I've got 0 in DataTable.
data.Tables["active"].Columns["Track"].DataType = Type.GetType("System.UInt32");
Is it possible to display every 0 in that column in DataGridView as an empty string (nothing)? But still have it stored as UInt32 0 in DataTable to be able to sort the tracks?
Sure, you can use the CellFormatting event:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].DataPropertyName == "Track")
{
uint value = (uint)e.Value;
if (value == 0)
{
e.Value = string.Empty;
e.FormattingApplied = true;
}
}
}
just a small suggestion ... add another column with "System.String" and make it's value equal to Track column (hide track column) and then you can replace 0 with empty string in the new visible column
An alternate CellFormatting function that displays an empty cell without changing the actual cell value:
private void dataGridView1_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (dataGridView1.Columns[e.ColumnIndex].DataPropertyName == "Track")
{
if (e.Value == 0)
{
e.CellStyle.Format = ";;;";
}
}