using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Globalization; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows; using System.Windows.Forms; namespace AdvertsingProfitControl { public partial class NewAddRecord : Form { private static readonly FrmLogConsole LogConsole = FrmLogConsole.GetStaticInstance; public NewAddRecord() { InitializeComponent(); //Assign the events that all APC DataGridViews will use. projectionsDataGridView.RowsAdded += DisplayRowNumbers; inventoryDataGridView.RowsAdded += DisplayRowNumbers; actualDataGridView.RowsAdded += DisplayRowNumbers; //Assign the events for the comments text box and display the remaining character count for the user. commentsTextBox.TextChanged += DisplayRemainingCommentCharacterCount; //commentsTextBox.KeyUp += DisplayRemainingCommentCharacterCount; commentsGroupBox.Text = @"Comments (Characters Remaining: " + commentsTextBox.MaxLength + @")"; /* * OnCellLeave(C1) OnRowLeave(R1) OnCellValidating(C1) OnCellValidated(C1) OnRowValidating(R1) OnRowValidated(R1) OnRowEnter(R2) OnCellEnter(C2) * */ //Setup the events for that the Projected and Actual Sales DataGridViews will share. //Events are assigned with regard to which event gets triggered first and so on.. projectionsDataGridView.CellValidating += ValidateSalesDataGridViewCellContents; actualDataGridView.CellValidating += ValidateSalesDataGridViewCellContents; } #region APC DataGridView Events /// /// Event Used: RowsAdded /// Draws the row number in the row's cell header whenever a row is added. /// /// /// private static void DisplayRowNumbers(object sender, DataGridViewRowsAddedEventArgs e) { var table = ((DataGridView)sender); table.Rows[e.RowIndex].HeaderCell.Value = (e.RowIndex + 1).ToString(); } #endregion #region Sales DataGridView Events /// /// Event Used: CellValidating /// Validates the contents of a cell, before leaving it. If the contents /// are valid then the appropriate formatting is applied if needed. /// /// /// private void ValidateSalesDataGridViewCellContents(object sender, DataGridViewCellValidatingEventArgs e) { //Grab the DataGirdView that fired the event and make it into a local variable. var dataGridView = ((DataGridView)sender); // var textInfo = new CultureInfo("en-US", false).TextInfo; //Check for isNewRow if it is, return no need to check it for anything. if (dataGridView.Rows[e.RowIndex].IsNewRow) { return; } //Check to see if the current column is the ad item column. if (e.ColumnIndex == 0) { var adItemText = dataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString(); //If there is text after all the whitespace has been cleared, clear the error text property regardless of whether or not it is set. if (!string.IsNullOrEmpty(Regex.Replace(adItemText, @"\s+", ""))) { //Clear the error text since there is in fact an item entered. dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = ""; //Send the ad item text through the formatting engine and assign the new value to the cell. dataGridView.Rows[e.RowIndex].Cells[0].Value = TextFormat.FormatAdItemText(adItemText); //Force a refresh so the cell's text updates and displays for the user. dataGridView.RefreshEdit(); return; } //If column one (1) is blank then cancel cell validating. if (e.ColumnIndex == 0 && Regex.Replace(adItemText, @"\s+", "") == "") dataGridView.Rows[e.RowIndex].Cells[0].ErrorText = "Ad Item needed"; return; } //Check to see if the cell is in the "Sold" column. if (e.ColumnIndex == 1) { //This Reg-ex pattern will match any number followed by the word bin(s), to allow specifying the number of bins of product were ordered. var inventoryStringCheck = new Regex(@"^[0-9]{1,2} \bbin(s){0,1}\b", RegexOptions.IgnoreCase); if ( inventoryStringCheck.IsMatch( dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString())) { //IF a match has been found, then make sure the word 'bin(s)' is capitalized to keep things looking pretty. var input = textInfo.ToTitleCase(dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString()); dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = input; dataGridView.RefreshEdit(); return; } } //If the column is the "Sale Price" column try to parse the contents to a Double and apply number formatting to the contents. //Check for the cost column to see if there are any strings formatted like such: var regExpression = new Regex(@"^\d+( *)?/( *)?\${0,1}?\d+(\.\d+)?", RegexOptions.IgnoreCase); // [0-9]/($)?[0-9] //IF the current cell is in the sale price column, check for the string format above, else move to the default method. if ((e.ColumnIndex == 2) && regExpression.IsMatch(dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString())) { //Grab the input and split it at the forward slash (/) for formatting. var input = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString(); input = input.Replace(" ", ""); //Remove any dollar signs as these cause errors. input = input.Replace("$", ""); var stringArray = input.Split('/'); //Format the last number as Currency, and round it up if necessary. dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = $@"{stringArray[0]}/{Math.Round(decimal.Parse(stringArray[1]), 2):C}"; //Always refresh edit so the new value shows up to the user. dataGridView.RefreshEdit(); return; //And return, there is no need to go further. } //If the column is any other then check to see if the entered value can be parsed to a double (is a number), if not then throw an error to the user. double parsedUserInput; if ( !double.TryParse( dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString(), out parsedUserInput)) { MessageBox.Show(@"Non numeric characters in column " + (e.ColumnIndex + 1) + @" are not allowed.", @"Invalid Characters Detected"); e.Cancel = true; dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = ""; dataGridView.RefreshEdit(); return; } //IF the index is greater then two (2), then that means we are not in a column that requires special formatting out side of currency. if (e.ColumnIndex <= 2) return; //IF not, then apply currency formatting to the cell. var value = double.Parse(dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString(), NumberStyles.Currency); //If all goes well, format the string in question by adding commas and decimal points if applicable. dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = Math.Round(value, 2).ToString("N", new CultureInfo("en-US")); //Always refresh edit so the new value shows up to the user. dataGridView.RefreshEdit(); } #endregion #region Comments TextBox Events /// /// Event Used: KeyUp /// Calculates and displays the remaining number of characters left available for the user to enter, /// and changes the color of the label displaying the character count to red when 20% or less characters remain. /// /// /// private void DisplayRemainingCommentCharacterCount(object sender, EventArgs e) { //If the amount of characters left is less then 20% (Or more 80% or more characters have been used) then color the label red, otherwise color it its default color. commentsGroupBox.ForeColor = (double)commentsTextBox.TextLength / commentsTextBox.MaxLength < .8 ? default(Color) : Color.DarkRed; commentsGroupBox.Text = @"Comments (Characters Remaining: " + (commentsTextBox.MaxLength - commentsTextBox.TextLength) + @")"; } #endregion #region MonthCalendar Events /// /// Updates the week ending masked text box with the selected date /// using the format (MM/DD/YYYY). /// /// /// private void UpdateWeekEndingMaskedTextBox(object sender, DateRangeEventArgs e) { var selectedDate = weekEndingMonthCalendar.SelectionStart; if (!selectedDate.ToString("D").StartsWith("Saturday")) { weekEndingMaskedTextBox.ForeColor = Color.Maroon; weekEndingMaskedTextBoxInstructionLabel.Text = @"... or manually enter it here: *"; errorLabel.Text = @"The date you selected does not appear to be a week ending date."; } else { weekEndingMaskedTextBox.ForeColor = Color.Black; weekEndingMaskedTextBoxInstructionLabel.Text = @"... or manually enter it here:"; errorLabel.Text = ""; } weekEndingMaskedTextBox.Text = selectedDate.ToString("MM-dd-yyyy"); } #endregion #region Data Grid View Construction Functions #endregion } }