I'm trying to add some bulletproofing in a DataGridView edit.
Columns 0, 1, 2, 3, 4 must have values to comply with datatable primary keys as well as SQL table constraints.
If any of the columns are blank I get either an internal exception on datatable primary keys or a SQL Exception on non nullable columns.
In the LeaveRow event, if any column values are null I'm calling CancelUpdate(). The problem is when CancelUpdate() executes, it is passing control to the top of the event and starting over.
Is this the correct behavior of CancelUpdate()?
Given my stated goal, is there another way I can accomplish?
.
private void dgvVX130_LeaveRow(object sender, DataGridViewCellEventArgs e)
{
bool z = true; // <======= CancelUpdate() passes execution to here
switch (dgvVX130.CurrentCell.ColumnIndex.ToString())
{
case "0":
if (dgvVX130.IsCurrentRowDirty &&
(dgvVX130.CurrentRow.Cells[1].Value.ToString() == "" ||
dgvVX130.CurrentRow.Cells[2].Value.ToString() == "" ||
dgvVX130.CurrentRow.Cells[3].Value.ToString() == ""))
{
z = false;
dgvVX130.CancelEdit(); // <=== Passes execution to top of event
MessageBox.Show("You must have Database, Schema, and TableName " +
"defined before leaving row"); // <===== Doesn't get executed
}
break;
case "1":
// Additional code is irrelevant
break;
}
}
Taking LarsTech suggestion I explored and used the RowValidating event. Was as simple as setting the CancelEventArgs.Cancel property to true. ( e.Cancel = True; )
private void dgvVX130_RowValidating(object sender, DataGridViewCellCancelEventArgs e)
{
switch (dgvVX130.CurrentCell.ColumnIndex.ToString())
{
case "0":
if (dgvVX130.IsCurrentRowDirty && (dgvVX130.CurrentRow.Cells[1].Value.ToString() == ""
|| dgvVX130.CurrentRow.Cells[2].Value.ToString() == ""
|| dgvVX130.CurrentRow.Cells[3].Value.ToString() == ""))
{
e.Cancel = true;
MessageBox.Show("You must have Database, Schema, and TableName defined before leaving row");
}
break;
case "1":
if (dgvVX130.IsCurrentRowDirty && (dgvVX130.CurrentRow.Cells[0].Value.ToString() == ""
|| dgvVX130.CurrentRow.Cells[2].Value.ToString() == ""
|| dgvVX130.CurrentRow.Cells[3].Value.ToString() == ""))
{
e.Cancel = true;
MessageBox.Show("You must have Database, Schema, and TableName defined before leaving row");
}
break;
Related
I want to make a condition like this
private void dataGridView1_KeyDown(object sender, KeyEventArgs e)
{
}
If the user selects the first column it will execute insert and if they select the third column it will execute edit
How do I go about doing this?
You need to check the selected columns, assuming they can only select one you can do this check
if(dataGridView1.SelectedColumns[0] == dataGridView1.Columns[0])
{
//Insert code;
}
else if(dataGridView1.SelectedColumns[0] == dataGridView1.Columns[2])
{
//Edit code;
}
If they can select multiple columns you should first do this check as well
if(dataGridView1.Columns.GetColumnCount(DataGridViewElementStates.Selected) == 1)
{
if(dataGridView1.SelectedColumns[0] == dataGridView1.Columns[0])
{
//Insert code;
}
else if(dataGridView1.SelectedColumns[0] == dataGridView1.Columns[2])
{
//Edit code;
}
}
Try this
if( dataGridView1.SelectedColumns[2] != null)
{
//Insertion
}
if( dataGridView1.SelectedColumns[0] != null)
{
//Editing
}
I am confused at my if statement that says if the textbox is null, has whitespace, empty string, contains specific characters or has regex characters, it will validate as correct. But instead, it validates as incorrect when I input text before losing focus as required by if-statement to pass. What am I doing wrong here? I notice adding an if(!(..)) will make it work the opposite way but that isn't correct logic and I'm confused.
// firstNameTB Textbox to dynamically check validation
private void firstNameTB_LostFocus(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(firstNameTB.Text) || firstNameTB.Text == "" || firstNameTB.Text.Contains("") || !Regex.IsMatch(firstNameTB.Text, #"^[A-Z]{1}[a-z]+$"))
{
firstNameTBL.Text = "First Name: *";
firstNameTBL.Foreground = new SolidColorBrush(Colors.Red);
firstNameTBL.FontWeight = FontWeights.Bold;
}
else
{
// set back to default layout
this.firstNameTBL.ClearValue(TextBlock.ForegroundProperty);
this.firstNameTBL.ClearValue(TextBlock.FontWeightProperty);
this.firstNameTBL.Text = "First Name:";
}
}
// lastNameTB Textbox to dynamically check validation
private void lastNameTB_LostFocus(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(lastNameTB.Text) || lastNameTB.Text == "" || lastNameTB.Text.Contains("") || !Regex.IsMatch(lastNameTB.Text, #"^[A-Z]{1}[a-z]+$"))
{
lastNameTBL.Text = "Last Name: *";
lastNameTBL.Foreground = new SolidColorBrush(Colors.Red);
lastNameTBL.FontWeight = FontWeights.Bold;
}
else
{
// set back to default layout
this.lastNameTBL.ClearValue(TextBlock.ForegroundProperty);
this.lastNameTBL.ClearValue(TextBlock.FontWeightProperty);
this.lastNameTBL.Text = "Last Name:";
}
}
// emailAddressTB Textbox to dynamically check validation
private void emailAddressTB_LostFocus(object sender, RoutedEventArgs e)
{
if (string.IsNullOrWhiteSpace(emailAddressTB.Text) || emailAddressTB.Text == "" || !(emailAddressTB.Text.Contains("#") && emailAddressTB.Text.Contains(".")))
{
emailAddressTBL.Text = "Email Address: *";
emailAddressTBL.Foreground = new SolidColorBrush(Colors.Red);
emailAddressTBL.FontWeight = FontWeights.Bold;
}
else
{
// set back to default layout
this.emailAddressTBL.ClearValue(TextBlock.ForegroundProperty);
this.emailAddressTBL.ClearValue(TextBlock.FontWeightProperty);
this.emailAddressTBL.Text = "Email Address:";
}
}
The problem lies in the ckecks to see whether textboxes contain empty strings e.g.:
... || lastNameTB.Text.Contains("") || ...
... || firstNameTB.Text.Contains("") || ...
Because these always evaluate to true - you get the behavior you described.
To fix this - simply remove these conditions from the if statements.
You can use String.Empty to check the String is empty or not:
if (string.IsNullOrWhiteSpace(lastNameTB.Text) ||
lastNameTB.Text == String.Empty ||
!Regex.IsMatch(lastNameTB.Text, #"^[A-Z]{1}[a-z]+$"))
{
}
In my datagridview, four columns 1 & 2 are read only col 3 & 4 got number values. I want to compare that 4th column must be greater that 3rd column.
For example:
If the 4th column value is less than the 3rd column then I want to propose message doesn't navigate to another control.
My simple approach seems not working. How can I compare 2 specific columns for this kind of condition?
private void datagridview_CellValidating(object sender, CellValidatingEventArgs e)
{
try
{
int bbor = datagridview.CurrentCell.ColumnIndex;
int ebor = datagridview.CurrentCell.RowIndex;
if (ebor <= bbor)
{
MessageBox.Show("Please verify the value");
e.Cancel = true;
}
}
catch (Exception exception)
{
}
}
we meet again. Use the cell_click event:
private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex != 0)
{
if (Double.Parse(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString()) <= Double.Parse(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex - 1].Value.ToString()))
{
MessageBox.Show("Please verify the value");
}
}
}
EDIT 1: This seems to work fine, lemme know.
private void dataGridView1_CellValidating(object sender, DataGridViewCellValidatingEventArgs e)
{
if (e.ColumnIndex != 0)
{
if (Double.Parse(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString()) <= Double.Parse(dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex - 1].Value.ToString()))
{
MessageBox.Show("Please verify the value");
e.Cancel = true;
}
}
}
Edit 2: Updated for Telerik controls
private void radGridView1_CellValidating(object sender, Telerik.WinControls.UI.CellValidatingEventArgs e)
{
if (e.ColumnIndex != 0)
{
if (e.Value != null && radGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex - 1].Value != null)
{
if (Double.Parse(e.Value.ToString()) <= Double.Parse(radGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex - 1].Value.ToString()))
{
MessageBox.Show("error");
e.Cancel = true;
}
}
}
}
I'd see something more or less like that:
If you want to check all rows:
DataRow dr;
for(int i = datagridview.Rows.Count-1; i > 0; i--) {
dr = datagridview.Rows[i];
if(dr[e.ColumnIndex] > dr[e.ColumnIndex+1]){
//your message code
e.Cancel = true;
break; (or return;)
}
}
If you want to check only the current row where the cell is being edited:
DataRow dr = datagridview.Rows[e.RowIndex];
e.Cancel = dr[e.ColumnIndex] > dr[e.ColumnIndex+1];
if(e.Cancel)
//your message code
Maybe you will need to convert objects to int for comparison.
See the Rows Property for DataGridView http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.rows.aspx
this.dataGridView1[col, row].Value
references a specific cell for each row
foreach (Row r in this.dataGridView1.Rows) {
if (r.Cells[3].Value <= r.Cells[2].Value ) {
System.Console.WriteLine ("error");
}
}
For your validation check you'll want to use the FormattedValue property to see what value your user wants to insert in the cell they've edited. You can't use the current cell value because it doesn't update to the new value until after the CellValidating completes without DataGridViewCellValidatingEventArgs.Cancel being set to true.
Something like this:
private void datagridview_CellValidating(object sender, DataGridViewCellValidatingEventArgs e) {
// This is the new proposed value the user entered; could be for column 3 or 4.
int newValue = int.Parse(e.FormattedValue.ToString());
// See which column fired the CellValidating event and use the new proposed value for it
// in place of the cell's actual value for purposes of our validation.
int col3Value = (e.ColumnIndex == 2) ? newValue : (int)dataGridView1[2, e.RowIndex].Value;
int col4Value = (e.ColumnIndex == 3) ? newValue : (int)dataGridView1[3, e.RowIndex].Value;
if (col3Value <= col4Value) {
MessageBox.Show("Please verify the value");
e.Cancel = true;
}
}
The code I show here is to demonstrate a solution to your problem. In your actual production code
you'll want to verify that casting from object to int is successful (through int.TryParse) or catch the exception that's raised when this operation fails. When this happens you can Cancel = true the cell validation and present to the user a message that he must enter a number.
And another quick note: don't use empty catch blocks (though I realize this probably isn't in your production code).
I am currently working with clicking count and textBox values. Button1 purpose is to execute an specific function depending on the value that texbox7 has. I am not getting any results when I try firing the button click event. Can someone suggest/help ?
Code
private List<string> messages = new List<string>() { "Option1", "Option2", "Option3", "Option4" };
private void button1_Click(object sender, EventArgs e)
{
if (textBox7.ToString() == "Option1")
{
int min = max;
int n = 0;
string s = "";
sw.Start();
}
else if (textBox7.ToString() == "Option2")
{
}
else if (textBox7.ToString() == "Option3")
{
}
else if (textBox7.ToString() == "Option4")
{
}
else if (textBox7.ToString() == "")
{
MessageBox.Show("Please input information");
}
}
Instead of
if (textBox7.ToString() == "Option1")
it should be
if (textBox7.Text == "Option1")
You should compare with the value inside the TextBox, and you can get that using Text property of the textbox.
Your textBox7.ToString() will give you something like System.Windows.Forms.TextBox, Text: text. Because of that you are not getting into any check. Compare your values against the Text property and it should work.
Check the TextBox.Text property in a switch-case statement:
private void button1_Click(object sender, EventArgs e)
{
switch (textBox7.Text)
{
case "Option1":
//do something
case "Option2":
//do something
case "Option3":
//do some thing
case "Option4":
//do something
break;
// If the value of switch-Expression is not 1, 2, 3 or 4 the
// default case is executed.
default:
MessageBox.Show("Please input information");
break;
}
}
It's Simple Use .Text property to get text value of textBox in code behind file
textBox7.Text property instead of
testBox7.ToString() further mode use either if-else statements or switch statement as these both are conditional statements and execution based on condition.
cheer up!
The title is only somewhat accurate. I'm trying to do something special with a textbox and the lack of certain events firing is causing some trouble, but I'd also like some general advice of how to do what it is I'm trying to do here. I'm trying to recreate a special textbox that exists on an old access application. It's for entering in a social security number, and when blank it displays ___-__-____.
When you click on any of the spaces it highlights the particular character. If you enter a number, it replaces the _ with that number. If you hit delete or backspace, it just replaces whatever character is highlighted with an _ or a -, depending.
I can sort of recreate this by having a textbox that is readonly and firing a PreviewMouseUp event to call a method that highlights the current cursor position. But since it's readonly it won't fire any KeyUp or KeyDown events to alter the selection. I can get it to do that if I put a KeyUp in the main UI grid, but it only works on KeyUp, so it winds up looking very laggy. Same issue with the PreviewMouseUp, I want it to highlight when the mouse is pressed down, not up, but PreviewMouseDown fires nothing.
I feel like I'm going about this in a messier and messier way. I've described what I want, does anyone have any better ideas of how to accomplish this that isn't super complicated? I want to keep the textbox readonly to allow me to handle the key inputs manually. What I mean is, My original way of formatting this was to simply run a method on KeyUp which checked the length of what you added and format it appropriately (add dashes, etc), but that results in this moment where everything looks unformatted until you release the key. For example, if I press '2' in the middle of the textbox it shifts all of the dashes over by a character until the '2' button is released, and then the formatting is fixed.
Thoughts?
It's funny how long I'd been working on this for now to finally get it, but the key was in AddHandler. For those of you who want a textbox like this, here's how I did it. There's a few messy bits in here, and those are simply to recreate the exact functionality of the access textbox. The most annoying part was implementing the backspace button, since it deletes what's before the selected section. Also, make sure your textbox is IsReadOnly.
In the constructor put:
textBox_ssn.AddHandler(Control.MouseDownEvent, new MouseButtonEventHandler(ClickSS), true);
textBox_ssn.AddHandler(Control.KeyDownEvent, new KeyEventHandler(ButtonSS), true);
Then use these two methods:
public void ClickSS(object sender, EventArgs e)
{
textBox_ssn.SelectionLength = 1;
}
public void ButtonSS(object sender, KeyEventArgs e)
{
bool on_first_char = false;
if (textBox_ssn.SelectionStart == 0) on_first_char = true;
if (e.Key == Key.Right && textBox_ssn.SelectionStart < 10)
{
++textBox_ssn.SelectionStart;
textBox_ssn.SelectionLength = 1; //Without this, it will move around large blocks of selection
if (textBox_ssn.SelectedText == "-") ++textBox_ssn.SelectionStart;
}
else if (e.Key == Key.Left && textBox_ssn.SelectionStart > 0)
{
--textBox_ssn.SelectionStart;
textBox_ssn.SelectionLength = 1;
if (textBox_ssn.SelectedText == "-") --textBox_ssn.SelectionStart;
}
else
{
string temp = "";
switch (e.Key)
{
case Key.D0:
temp = "0";
break;
case Key.D1:
temp = "1";
break;
case Key.D2:
temp = "2";
break;
case Key.D3:
temp = "3";
break;
case Key.D4:
temp = "4";
break;
case Key.D5:
temp = "5";
break;
case Key.D6:
temp = "6";
break;
case Key.D7:
temp = "7";
break;
case Key.D8:
temp = "8";
break;
case Key.D9:
temp = "9";
break;
case Key.Delete:
temp = "_";
break;
case Key.Back:
temp = "_";
if (textBox_ssn.SelectionStart > 0) --textBox_ssn.SelectionStart;
if (textBox_ssn.SelectedText == "-") --textBox_ssn.SelectionStart;
//else return; //or could do temp = selection text but only if selection length is 1 ectect
break;
}
if (temp != "")
{
if (textBox_ssn.SelectionLength > 1)
{
string underscores = "";
foreach (char c in textBox_ssn.SelectedText)
{
if (c == '-') underscores += "-";
else underscores += "_";
}
textBox_ssn.SelectedText = underscores;
textBox_ssn.SelectionLength = 1;
}
if (textBox_ssn.SelectedText == "-") ++textBox_ssn.SelectionStart;
if (textBox_ssn.SelectionLength == 1)
{
if (!(on_first_char && e.Key == Key.Back)) textBox_ssn.SelectedText = temp;
if (e.Key == Key.Delete) ;
else if (e.Key == Key.Back)
{
if (textBox_ssn.SelectionStart > 0)
{
//--textBox_ssn.SelectionStart;
if (textBox_ssn.SelectedText == "-") --textBox_ssn.SelectionStart;
}
}
else
{
++textBox_ssn.SelectionStart;
if (textBox_ssn.SelectedText == "-") ++textBox_ssn.SelectionStart;
}
}
}
}
}
What you are describing is known as a Masked Textbox. There is a free one in the VisualStudioGallery and in the Extended WPF ToolKit