Using DataGridViewComboBoxColumn for distinct options - c#

I'm modifying a Winforms application in .NET 3.5.
I have a DataGridViewComboBoxColumn populated with some hard coded options as shown below.
//
// dgvCol_PropName
//
this.dgvCol_PropName.DisplayStyle = System.Windows.Forms.DataGridViewComboBoxDisplayStyle.ComboBox;
this.dgvCol_PropName.HeaderText = "Property Name";
this.dgvCol_PropName.Items.AddRange(new object[] {
"Option1",
"Option2",
"Option3"});
this.dgvCol_PropName.Name = "dgvCol_PropName";
this.dgvCol_PropName.Width = 150;
I would like to make the selection of these options distinct so that once an option exists in the grid then it can't be selected again (The user should edit the current row or delete and re-enter it).
Is there a quick way to do this?
I thought I'd share my final solution in case it helps anyone else. My CellValidating event handler is below:
/// <summary>
/// Handle the validation event on the cell so that only properties that have not already been specified can be selected
/// </summary>
private void dg_FTPS_ExProps_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
var dataGrid = sender as DataGridView;
if (dataGrid != null)
{
// Only validate if that event is generated for the Property Name column
string headerText = dataGrid.Columns[e.ColumnIndex].HeaderText;
// Abort validation if cell is not in the PropertyName column.
// Rejected using the column index in case the column order changes but
// equally, there will be problems if the column header changes. (Pay your money and take a chance)
if (headerText.Equals("Property Name"))
// if (e.ColumnIndex == 0)
{
// Count the number of times the property exists in the table
int propertyCount = 0;
foreach (DataGridViewRow row in dg_FTPS_ExProps.Rows)
{
if( row.Cells[ e.ColumnIndex ].EditedFormattedValue.ToString().Equals( e.FormattedValue) == true )
{
propertyCount++;
}
}
// Check if multiple entreies have tried to be applied
if (propertyCount > 1)
{
e.Cancel = true;
}
}
}
}
I'd have liked to use LINQ to count the number of instances but I'm still learning that so I stuck to what I know.

Try using this event DataGridView.CellValidating in the body of the event just check if there is another row with same value and if there is just set e.Cancel to true.

Related

Compare cells value in gridview for greater value c#

i want to check if obtained marks are not greater than total marks in a gridview while entering data in runtime. what is the best way to implement that?
the logic i have developed is something like this:
if(DG_Result .Rows .Count >0)
{
for(int x=0;x<DG_Result .Rows .Count ;x++)
{
if(DG_Result .Rows [x].Cells ["DGTotal"].Value !="" & DG_Result .Rows [x].Cells ["DGObt"].Value !="")
{
if(Convert .ToInt32(DG_Result .Rows [x].Cells ["DGObt"].Value)>Convert .ToInt32(DG_Result .Rows [x].Cells ["DGTotal"].Value ))
{
DG_Result.Rows[x].Cells["DGObt"].Value = "";
MessageBox.Show("Obtained Marks Cannot be greater than Total Marks");
}
}
}
}
but i am not sure which event shall i use for this. i used timer but its not working. any suggestions? Cheers
Attach an event handler to your datagridview. Imaging it is called dataGridView1:
this.dataGridView1.CellValidating += new
DataGridViewCellValidatingEventHandler(dataGridView1_CellValidating);
Then write the event handler where you will have your validation logic:
private void dataGridView1_CellValidating(object sender,
DataGridViewCellValidatingEventArgs e)
{
string headerText =
dataGridView1.Columns[e.ColumnIndex].HeaderText;
// Abort validation if cell is not in the target column.
// The target column is the column you want to validate
if (!headerText.Equals("TargetColumn")) return;
// Confirm that the cell is not empty.
if (string.IsNullOrEmpty(e.FormattedValue.ToString()))
{
dataGridView1.Rows[e.RowIndex].ErrorText =
"Your error message goes here.";
e.Cancel = true;
}
}
You can read more about validation here.

Set DataGridViewComboBox default equal to existing DataGridView column

I have added a DataGridViewComboBox to a bound DataGridView (grdBOOK), the DataGridViewComboBox will replace column 3 to allow for user selection. I'm struggling to set the default of the DataGridViewComboBox equal to the value of column 3 so user selection is not required if the value is correct.
I pulled the code below from the net, but I get an error:
DataGridViewComboBoxCell value is not valid.
I thought a ComboBox cell could be treated as a normal DataGridView cell, but (see code below) an error is generated when a string is added to the ComboBox column? I've trawled the net and SO for a few days but nothing works, any suggestions please?
public void BOOK_COMBO2()
{
DataGridViewComboBoxCell cb_cell = new DataGridViewComboBoxCell();
DataGridViewComboBoxColumn cb_col = new DataGridViewComboBoxColumn();
// Contract field
cb_col.Items.AddRange("YEARLY", "MONTHLY", "");
cb_col.FlatStyle = FlatStyle.Flat;
cb_col.HeaderText = "newCONTRACT";
cb_col.Width = 50;
cb_col.ValueType = typeof(string);
// Add ComboBox and test
grdBOOK.Columns.Insert(5, cb_col);
grdBOOK.Rows[14].Cells[4].Value = "zzz"; // No error adding string to normal dgv column
grdBOOK.Rows[14].Cells[5].Value = "xxx"; // Error adding string to dgvcombobx column
//copy old values to new combobox and set as default
foreach (DataGridViewRow item in grdBOOK.Rows)
{
item.Cells[5].Value = item.Cells[3].Value;
}
//hide original column
grdBOOK.Columns[3].Visible = false;
}
After more research on the net, IMHO using a ContextMenuStrip is a better method of achieving this. Link here. A ContextMenuStrip has better methods, events, properties etc. I hope this helps others looking for a solution.
private void dataGridView1_DataError(object sender,
DataGridViewDataErrorEventArgs e)
{
// If the data source raises an exception when a cell value is
// commited, display an error message.
if (e.Exception != null &&
e.Context == DataGridViewDataErrorContexts.Commit)
{
MessageBox.Show("");
}
}
private void Form1_Load(object sender, EventArgs e)
{ dataGridView1.DataError +=
dataGridView1_DataError;}

How to set the focus on the next/previous cell inside a DataGrid? Especially after calling grid.CommitEdit()?

I've a custom combobox template because of some binding stuff that won't work with the 'default' ComboBoxColumn.
To make it look 'nice' I've one template for the edit mode (a Combobox) and one for the 'normal' mode (a Label).
Now, because of that I've to commit the edit made to the combobox manually inside the CellEditEnding event
private bool changeCommitInProgress = false;
private void table_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
if (e.EditingElement is ContentPresenter && e.EditAction == DataGridEditAction.Commit)
{
if (!changeCommitInProgress)
{
changeCommitInProgress = true;
DataGrid grid = (DataGrid)sender;
grid.CommitEdit(DataGridEditingUnit.Row, false);
changeCommitInProgress = false;
}
}
}
The problem with this is, that it'll remove the focus from the entire datagrid. Just to be on the safe side, these are the only properties I changed on the datagrid (aside from the Name property and the ItemsSource):
grid.AutoGenerateColumns = false;
grid.IsSynchronizedWithCurrentItem = true;
grid.SelectionUnit = DataGridSelectionUnit.Cell;
This is a fun question. I have done similar with a nested DataList where I had to add a new row after last entry and focus on the first textbox of the newly generated row, maybe you can extrapolate my strategy to fit your situation?
protected void calcAvg(object sender, CommandEventArgs e)
{
int row = Convert.ToInt32(e.CommandArgument.ToString()) - 1;
DataListItem ActiveRow = dlMeasurements.Items[row];
// Snipped code doing stuff with current row
// Compare how many rows completed to number of rows requested
if (!(row + 1 == Convert.ToInt32(txtSample.Text)))
{
// Create new row
DataRow drNew = nextMeas.Tables[0].NewRow();
nextMeas.Tables[0].Rows.Add(drNew);
// Change item index and rebind
dlMeasurements.EditItemIndex = row + 1;
dlMeasurements.DataSource = nextMeas.Tables[0];
dlMeasurements.DataBind();
//Set focus with the Script Manager
smInspection.SetFocus((TextBox)(dlMeasurements.Items[row + 1].FindControl("txtRead1")));
}
else
{
// Otherwise close the measurements and show exit button
dlMeasurements.EditItemIndex = -1;
dlMeasurements.DataSource = nextMeas.Tables[0];
dlMeasurements.DataBind();
btnSaveAndPrint.Visible = true;
}
}
}

datagrid selected index gives troubles

I have a datagrid that I fill with data from a database.
When I click on a row, I call the GotFocus method and try to make a button visible if certain requirements are met.
private void dtgVerkoopsdocumenten_GotFocus(object sender, RoutedEventArgs e)
{
DataItem row = (DataItem)dtgVerkoopsdocumenten.SelectedItems[0];
if (row.soort2 == "Factuur")
{
btnBoeking.IsHitTestVisible = true;
btnBoeking.Opacity = 1;
}
else
{
btnBoeking.IsHitTestVisible = false;
btnBoeking.Opacity = 0.5;
}
}
This gives me an error.
Index was out of range. Must be non-negative and less than the size of the collection.
Now when I call the code but from a button click it does it how it's supposed to work.
private void tester_Click(object sender, RoutedEventArgs e)
{
DataItem row = (DataItem)dtgVerkoopsdocumenten.SelectedItems[0];
test.Content = row.soort2;
if (row.soort2 == "Factuur")
{
btnBoeking.IsHitTestVisible = true;
btnBoeking.Opacity = 1;
}
else
{
btnBoeking.IsHitTestVisible = false;
btnBoeking.Opacity = 0.5;
}
}
Why is this?
Why dont you use DataGrid SelectedIndexChanged event?
Wyy use GotFocus that doesnt tell you if user even made a selection to start with,
DataItem row = (DataItem)dtgVerkoopsdocumenten.SelectedItems[0];
Called from gotfocus will fail as you have nothing selected besides having no error check in place to check if selection,
If you use Selection changed events you know the user has made selection changes there are a number of events for selection
before access selected items by index you need to check selected item count is grater than zero condition.
Because dtgVerkoopsdocumenten.SelectedItems are empty and GotFocus event raise before SelectedItemChanged event so we are not sure the dtgVerkoopsdocumenten.SelectedItems have any item or not.
You can check dtgVerkoopsdocumenten.SelectedItems before do anything.
if (dtgVerkoopsdocumenten.SelectedItems != null &&
dtgVerkoopsdocumenten.SelectedItems.Count > 0)
{
DataItem row = (DataItem)dtgVerkoopsdocumenten.SelectedItems[0];
...
}

How to disable a row by selecting value from comboBox in datagridview?

Here I have a column name "Status" in which I am using ComboBox whose values are "Pending" and "Delivered" now I want that when a user selects the delivered from the ComboBox then the entire row or this control should be disabled so user could not change it again and by default its value should be "Pending" how can i do it? Is it possible to disable a single row in gridview?
You cannot disable an individual row. However you can make it readonly:
DataGridView1.Rows[rowIndex].ReadOnly = true;
(This makes row with index of rowIndex set to readonly).
For your specific example, you would want to handle the CellValueChanged event of the datagridview and have code along the lines of:
void DataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == 4 && DataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString() == "Delivered")
{
DataGridView1.Rows[e.RowIndex].ReadOnly = true;
}
}
You can handle the RowChanged event and do something like
if (Status == 'Delivered')
{
e.Row.Enabled = False;
}

Categories

Resources