using System; using System.Collections.Generic; using System.ComponentModel; using System.Drawing; using System.Text.RegularExpressions; using System.Globalization; using System.Windows.Forms; using DataTableParsingEngine; namespace AdvertsingProfitControl { public partial class FrmAddRecord : Form { //http://stackoverflow.com/questions/392397/why-do-we-use-arrays-instead-of-other-data-structures Structures of arrays. //Reordering rows: http://stackoverflow.com/questions/1620947/how-could-i-drag-and-drop-datagridview-rows-under-each-other/1623968#1623968 private int _gLastRowHeaderIndex = -1; //Keep track of the AdSpecial row's index, both table's AdSpecial row will have the same row index value. private int _gAdSpecialIndex = -1; //Create an object to interact with the logging form. readonly FrmLogConsole _gLogConsole = FrmLogConsole.GetStaticInstance; private List _gAdItemCollection = new List(); private AutoCompleteStringCollection _gSupplierCollection = new AutoCompleteStringCollection(); private AutoCompleteStringCollection _CustomAdItemCollection = new AutoCompleteStringCollection(); private AutoCompleteStringCollection _AdSpecialList = new AutoCompleteStringCollection(); //This array keeps track of the number of times an Ad Item is used, if used once then it may only be used AFTER an AdSpecialRow and only once after that. //Once an item has been used twice, it will not appear again in the AutoCompleteSuggestions. //Structure: "ADITEMSTRING":"SECTIONUSED" Section used means what side of the AdSpecialRow, one (1) being before and two (2) being after. private readonly List _gUsedAdItems = new List(); //This string keeps track of the last ad item used. This item can then be used to safely remove an ad item from the list of used items. //Used in the OnCellValidating event to store the last ad item used in the event that the user changes a row that already exists. private string _gLastAdItemEntered = ""; public FrmAddRecord() { InitializeComponent(); } private void frmAddRecord_Load(object sender, EventArgs e) { //Start by grabbing all the AdItems and putting them into memory. //var databaseTracker = new DatabaseTracker(); //var databaseReader = new DatabaseReader(); //_gAdItemCollection = databaseReader.GetAdItemsSuggestionList(databaseTracker.DatabaseConnectionString); // weekEndingDateMaskedTextBox.Leave += OnWeekEndingDateMaskedTextBoxLeave; //Now pull all the suppliers into memory. //_gSupplierCollection = databaseReader.GetSupplierSuggestionList(databaseTracker.DatabaseConnectionString); //_AdSpecialList = databaseReader.RetrieveAdSpecialList(databaseTracker.DatabaseConnectionString); //Event handlers for the Projections DataGridView projectionsDataGridView.CellValidating += OnCellValidating; //projectionsDataGridView.RowEnter += DetectAndDisplayIncompleteRows; projectionsDataGridView.RowLeave += OnRowLeave; projectionsDataGridView.RowsAdded += DisplayRowNumbers; projectionsDataGridView.RowsRemoved += OnRowRemoved; projectionsDataGridView.UserDeletingRow += OnRowRemoving; projectionsDataGridView.EditingControlShowing += DisplayAutoCompleteOnEditingControlShowing; projectionsDataGridView.RowValidating += UpdateInventoryActualSalesDataGridView; //Event handlers for the Inventory / Actual Sales DataGridView actualSalesDataGridView.CellValidating += OnCellValidating; // actualSalesDataGridView.RowEnter += DetectAndDisplayIncompleteRows; actualSalesDataGridView.RowLeave += OnRowLeave; // actualSalesDataGridView.RowsAdded += DisplayRowNumbers;// actualSalesDataGridView.RowsRemoved += OnRowRemoved;// actualSalesDataGridView.UserDeletingRow += OnRowRemoving; // actualSalesDataGridView.EditingControlShowing += DisplayAutoCompleteOnEditingControlShowing; // actualSalesDataGridView.RowValidating += UpdateProjectionsDataGridView;// //Event handlers for the Suppliers DataGridView suppliersDataGridView.CellValidating += SupplierOnCellValidating; suppliersDataGridView.EditingControlShowing += DisplaySupplierNameAutoComplete; //Event handlers for the Weekly Sales DataGridView weeklySalesDataGridView.CellValidating += FormatWeeklySalesOnCellValidating; //Builds the DataGridViews ConstructDataGridViews(); } //Begin DataGridView event handlers /// /// Event Used: Leave /// Attempts to parse the date entered when the user leaves the DateMaskedTextbox. /// Clears the date if it is invalid, otherwise formats it and places it in the textbox. /// /// /// private void OnWeekEndingDateMaskedTextBoxLeave(object sender, EventArgs e) { string input = weekEndingDateMaskedTextBox.Text; input = input.Replace(" ", ""); //The forwardslashes "/" in the masked textbox are sent programmically as spaces. DateTime processedDate; if (!DateTime.TryParse(input, out processedDate)) { weekEndingDateMaskedTextBox.Clear(); MessageBox.Show(@"Failed to convert the date input.", @"Date Conversion Error"); } else { weekEndingDateMaskedTextBox.Text = processedDate.ToString("MM/dd/yyyy"); } } /// /// Event Used: CellValidating /// Performs formatting and validation based on what column the cell is in. /// /// /// private void OnCellValidating(object sender, DataGridViewCellValidatingEventArgs e) { var dataGridView = ((DataGridView)sender); TextInfo 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) { string 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 (adItemText.Replace(" ", "") != "") { //Clear the error text since there is in fact an item entered. dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = ""; //Check for the reserved character, and remove it if it is found. if (adItemText.Contains(":")) { _gLogConsole.WriteToLog(FrmLogConsole.Level.Warning, "Colon (:) is a reserved character and therefore not allowed to be used in an ad item name."); adItemText = adItemText.Replace(":", ""); } //Pretty up the ad item's name by uppercasing the name. adItemText = textInfo.ToTitleCase(adItemText); //Eliminate the upper cased pound abbreviation ("Lb") with a standard "lb". var rgx = new Regex("Lb"); adItemText = rgx.Replace(adItemText, "lb"); dataGridView.Rows[e.RowIndex].Cells[0].Value = adItemText; dataGridView.RefreshEdit(); return; } if (e.ColumnIndex == 0 && adItemText == "") //Otherwise, set the error text to inform the user. { dataGridView.Rows[e.RowIndex].Cells[0].ErrorText = "Ad Item needed"; return; } } //Make an ugly check for the Inventory / Actual Sales table, and perform logic on the inventory columns to allow 'Bin(s) [0-9]'. if (dataGridView.Name == "inventoryActualSalesDataGridView" && e.ColumnIndex > 0 && e.ColumnIndex < 6 || dataGridView.Name == "projectionsDataGridView" && e.ColumnIndex == 1) { var invenotryStringCheck = new Regex(@"^[0-9] \bbin(s){0,1}\b", RegexOptions.IgnoreCase); if ( invenotryStringCheck.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; } } //Check to see if whether or not the current cell is not in the first column and not empty. if (e.ColumnIndex != 0 && !string.IsNullOrEmpty(dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString())) { //IF so, 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); //IF the current cell is in the cost column, check for the string format above, else move to the default method. if ((dataGridView.Columns[e.ColumnIndex].Name == "PrSalePrice" || dataGridView.Columns[e.ColumnIndex].Name == "AcSalePrice") && regExpression.IsMatch(dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString())) { //Grab the input and split it at the forward slash (/) for formatting. string input = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString(); input = input.Replace(" ", ""); //Remove any dollar signs as these cause errors. input = input.Replace("$", ""); string[] stringArray = input.Split('/'); //Format the last number as Currency, and round it up if necessary. dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = String.Format(@"{0}/{1:C}", stringArray[0], Math.Round(Decimal.Parse(stringArray[1]), 2)); //Always refresh edit so the new value shows up to the user. dataGridView.RefreshEdit(); } else { //Check to see if the entered value can be parsed to a double, if not then throw an error to the user. double doubleOuts = 0; if ( !double.TryParse( dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString(), out doubleOuts)) { _gLogConsole.WriteToLog(FrmLogConsole.Level.Error, "The cell in column " + (e.ColumnIndex + 1) + " row " + (e.RowIndex + 1) + " only allows for numeric input."); 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; } //Check to see if the current DataGridView is the Inventory / Actual Sales grid or the Projections grid. if (dataGridView.Name == "inventoryActualSalesDataGridView") { //Check to make sure the cell is not in the Inventory / Sold columns. if (e.ColumnIndex > 5) { //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(); } } else { //IF the current column is not the Sold column then apply currency formatting if numeric. if (e.ColumnIndex != 1) { //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(); } } } } }//End OnCellValidating /// /// Event Used: RowEnter /// Spins through the index values of incomplete rows and displays to the user /// which ones will not be included in the database if they attempt to add the record. /// /// A reference to the DataGridView that fired the event. /// private void DetectAndDisplayIncompleteRows(Object sender, DataGridViewCellEventArgs e) { var message = ""; var incompleteRows = new List(); var dataGridView = ((DataGridView)sender); var i = 0; //Get the indexes of all incomplete rows. for (var index = 0; index < dataGridView.Rows.Count; index++) { var row = dataGridView.Rows[index]; if (!row.IsNewRow && row.Cells[0].ErrorText != "") { incompleteRows.Add(i); } i++; } //Make the error message all nice and formatted, purely anesthetic. if (incompleteRows.Count <= 0) return; { i = 0; foreach (int index in incompleteRows) { //Formatting for one item in the array. if (incompleteRows.Count == 1) { message = "Row " + (index + 1); } else if (incompleteRows.Count == 2) { //Formatting for 2 items in the array. if (i == 0) { message = "Rows " + (index + 1) + " and "; } else { message += (index + 1).ToString(); } } else { //Formatting for 3 or more items in the array. if (i == 0) //Checks for the first entry in the array. { message = "Rows " + (index + 1) + ", "; } else if (i < incompleteRows.Count - 2) //Detects all the entries in between. { message += (index + 1) + ", "; } else if (i == incompleteRows.Count - 2) //Detects for the second to last item in the array, so get rid of the comma (,). { message += (index + 1).ToString(); } else //Fires only on the last entry in the array. { message += " and " + (index + 1); } } i++; } message += " will not be included in the database because no ad item is specified."; _gLogConsole.WriteToLog(FrmLogConsole.Level.Error, message); } } //End DetectAndDisplayIncompleteRows /// /// Event Used: RowLeave /// /// /// /// private void OnRowLeave(object sender, DataGridViewCellEventArgs e) { var dataGridView = ((DataGridView)sender); PaintRowsOnLeave(e.RowIndex, dataGridView); //Add in used Ad Items to the list. if (dataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString() == "") return; //Section one (1) detected. if (_gAdSpecialIndex == -1 || e.RowIndex < _gAdSpecialIndex) { if (_gUsedAdItems.Contains(dataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString())) return; if (!_gUsedAdItems.Contains(dataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue + ":1")) { _gUsedAdItems.Add(dataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue + ":1"); } } //Section two (2) detected. else if (e.RowIndex > _gAdSpecialIndex) { if (_gUsedAdItems.Contains(dataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString())) return; if (!_gUsedAdItems.Contains(dataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue + ":2")) { _gUsedAdItems.Add(dataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue + ":2"); } } }//End OnRowLeave /// /// Event Used: RowsAdded /// Adds the row's number to the Row Header Cell whenever a new row is added. /// /// The DataGridView that is getting new rows added to it. /// Row arguments, like row index private void DisplayRowNumbers(object sender, DataGridViewRowsAddedEventArgs e) { var table = ((DataGridView)sender); table.Rows[e.RowIndex].HeaderCell.Value = (e.RowIndex + 1).ToString(); } /// /// Event Used: RowsRemoved /// Fires after the row has been removed. This function removes the other DataGridView's row at the index /// specified in the e.RowIndex argument, ensuring that the tables are uniform as to not cause data corruption in the database. /// /// /// private void OnRowRemoved(object sender, DataGridViewRowsRemovedEventArgs e) { var dataGridView = ((DataGridView)sender); //Provide protection against overflows if ((e.RowIndex + 1) > dataGridView.Rows.Count) { return; } //Check to see what DataGridView fired the event and delete the other's row at the e.RowIndex. if (dataGridView.Name == "projectionsDataGridView") { //First, un-subscribe the row remove events... actualSalesDataGridView.RowsRemoved -= OnRowRemoved; actualSalesDataGridView.UserDeletingRow -= OnRowRemoving; //IF the row count on the passed DataGridView is less then the other table's row count... if (projectionsDataGridView.RowCount <= actualSalesDataGridView.RowCount) { //... it is lower so its safe to assume that both tables have the same row that can be removed. if (!actualSalesDataGridView.Rows[e.RowIndex].IsNewRow) { actualSalesDataGridView.Rows.RemoveAt(e.RowIndex); } } //ELSE IF the row count is larger then the other table's row count... else { //... } //... After all the row removal has been finished re-enable the row removal events. actualSalesDataGridView.RowsRemoved += OnRowRemoved; actualSalesDataGridView.UserDeletingRow += OnRowRemoving; } else if(dataGridView.Name == "inventoryActualSalesDataGridView" && actualSalesDataGridView.RowCount <= projectionsDataGridView.RowCount) { //First, un-subscribe the row remove events.... projectionsDataGridView.RowsRemoved -= OnRowRemoved; projectionsDataGridView.UserDeletingRow -= OnRowRemoving; //IF the row count on the passed DataGridView is less then the other table's row count... if (actualSalesDataGridView.RowCount <= projectionsDataGridView.RowCount) { //... it is lower so its safe to assume that both tables have the same row that can be removed. if (!projectionsDataGridView.Rows[e.RowIndex].IsNewRow) { projectionsDataGridView.Rows.RemoveAt(e.RowIndex); } } else { //... } //... After all the row removal has been finished re-enable the row removal events. projectionsDataGridView.RowsRemoved += OnRowRemoved; projectionsDataGridView.UserDeletingRow += OnRowRemoving; } //Reset the row numbers in the tables. for (int i = e.RowIndex; i < (dataGridView.RowCount); i++) { projectionsDataGridView.Rows[i].HeaderCell.Value = (i + 1).ToString(); actualSalesDataGridView.Rows[i].HeaderCell.Value = (i + 1).ToString(); } //Refresh the DataGridViews so the header cell's number get repainted properly and repaint the rows in case any groups get messed up during row removal. projectionsDataGridView.RefreshEdit(); actualSalesDataGridView.RefreshEdit(); PaintRowGroups(dataGridView); } /// /// Event Used: UserDeleteingRow /// This function is responsible for removing ad Items from the gUsedAdItem array; this must be done during the row removing /// event handler so the data in the row can be grabbed and used. /// /// The DataGridView that fired the event. /// Parameters, mainly allowing for canceling the event. private void OnRowRemoving(object sender, CancelEventArgs e) { //Create an object that represents the DataGridView that fired the event. var dataGridView = ((DataGridView)sender); if (dataGridView.CurrentRow == null) return; var currentRowIndex = dataGridView.CurrentRow.Index; //Remove the ad item from the gUsedAdItem collection, if it exists. if (_gAdSpecialIndex == -1 || currentRowIndex < _gAdSpecialIndex) { //If the ad item entered in the first cell is in the gUsedAdItems collection, then remove it from there. if (_gUsedAdItems.Contains(dataGridView.Rows[currentRowIndex].Cells[0].EditedFormattedValue.ToString() + ":1")) { //This is section one (1) since it occurs before the adSpecial row. _gUsedAdItems.RemoveAll(I => I.Equals(dataGridView.Rows[currentRowIndex].Cells[0].EditedFormattedValue.ToString() + ":1", StringComparison.OrdinalIgnoreCase)); } } else if (currentRowIndex > _gAdSpecialIndex) { //If the ad item entered in the first cell is in the gUsedAdItems collection, then remove it from there. if (_gUsedAdItems.Contains(dataGridView.Rows[currentRowIndex].Cells[0].EditedFormattedValue.ToString() + ":2")) { //This is section two (2) since it after the adSpecial row. _gUsedAdItems.RemoveAll(I => I.Equals(dataGridView.Rows[currentRowIndex].Cells[0].EditedFormattedValue.ToString() + ":2", StringComparison.OrdinalIgnoreCase)); } } else if (currentRowIndex == _gAdSpecialIndex) { //Handle removing the AdSpecial row. DialogResult result = MessageBox.Show("Deleting the Ad Special row will remove all rows beneath it.\nDo you wish to continue?", "Clear " + dataGridView.Rows[currentRowIndex].Cells[0].EditedFormattedValue, MessageBoxButtons.YesNo); if (result == DialogResult.Yes) { //Clear all events that handle row removal from both DataGridViews. //Projections table projectionsDataGridView.RowsRemoved -= OnRowRemoved; projectionsDataGridView.UserDeletingRow -= OnRowRemoving; //Inventory / Actual Sales table actualSalesDataGridView.RowsRemoved -= OnRowRemoved; actualSalesDataGridView.UserDeletingRow -= OnRowRemoving; //Now for-each through each row that is underneath the Ad Special row. for (var rowIndex = currentRowIndex; rowIndex < (dataGridView.RowCount -1); rowIndex++) { //If the ad item entered in the first cell is in the gUsedAdItems collection, then remove it from there. if (_gUsedAdItems.Contains(dataGridView.Rows[currentRowIndex].Cells[0].EditedFormattedValue.ToString() + ":2")) { //This is section two (2) since its after the adSpecial row. _gUsedAdItems.RemoveAll(I => I.Equals(dataGridView.Rows[currentRowIndex].Cells[0].EditedFormattedValue.ToString() + ":2", StringComparison.OrdinalIgnoreCase)); } if (projectionsDataGridView.Rows[currentRowIndex].IsNewRow != true) { projectionsDataGridView.Rows.RemoveAt(currentRowIndex); } if (actualSalesDataGridView.Rows[currentRowIndex].IsNewRow != true) { actualSalesDataGridView.Rows.RemoveAt(currentRowIndex); } } //Re-enable all row removal events on both tables. //Projections table projectionsDataGridView.RowsRemoved += OnRowRemoved; projectionsDataGridView.UserDeletingRow += OnRowRemoving; //Inventory / Actual Sales table actualSalesDataGridView.RowsRemoved += OnRowRemoved; actualSalesDataGridView.UserDeletingRow += OnRowRemoving; //Reset the gAdSpecialIndex to -1. _gAdSpecialIndex = -1; e.Cancel = true; //Prevent the new row from being removed. } else { e.Cancel = true; } } } /// /// Event Used: OnEditingControlShowing /// Configures the auto complete collection and how it will be shown to the user. This method detects the section, /// either one (1) or two (2), based on the gAdSpecialIndex and removes items from the auto complete accordingly. /// Just a measure to help reduce redundancy in the tables. /// /// /// private void DisplayAutoCompleteOnEditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) { var dataGridView = ((DataGridView)sender); var autoText = e.Control as TextBox; if (e.Control is DataGridViewTextBoxEditingControl && dataGridView.CurrentCell.ColumnIndex == 0) { //Create a copy of the main ad item list that can be freely manipulated. var customAutoComplete = new AutoCompleteStringCollection(); var customList = new List(); foreach (string item in _gAdItemCollection) { customList.Add(item); } //IF the current row is less than the AdSpecialRow, remove all used items with the section 1 attribute. if (_gAdSpecialIndex == -1 || dataGridView.CurrentCell.RowIndex < _gAdSpecialIndex) { if (_gUsedAdItems != null) { foreach (var adItem in _gUsedAdItems) { string[] adItemString = adItem.Split(':'); string section = adItemString[1]; string adItemToRemove = adItemString[0]; if (section == "1") { customList.RemoveAll( w => w.Equals(adItemToRemove, StringComparison.OrdinalIgnoreCase)); } } } } //Occurs AFTER the AdSpecial row. else if (dataGridView.CurrentCell.RowIndex > _gAdSpecialIndex) { if (_gUsedAdItems != null) { foreach (string adItem in _gUsedAdItems) { string[] adItemString = adItem.Split(':'); string section = adItemString[1]; string adItemToRemove = adItemString[0]; if (section == "2") { customList.RemoveAll( w => w.Equals(adItemToRemove, StringComparison.OrdinalIgnoreCase)); } } } } foreach (var item in customList) { customAutoComplete.Add(item); } autoText.KeyDown += AutoText_KeyPress; _CustomAdItemCollection = customAutoComplete; //Make a temporary copy of the list for use with the TextBox event handler. autoText.AutoCompleteMode = AutoCompleteMode.Suggest; autoText.AutoCompleteSource = AutoCompleteSource.CustomSource; autoText.AutoCompleteCustomSource = customAutoComplete; } else if(e.Control is DataGridViewTextBoxEditingControl && dataGridView.CurrentCell.ColumnIndex != 0) { autoText.AutoCompleteMode = AutoCompleteMode.None; } }//End DisplayAutoCompleteOnEditingControlShowing private void AutoText_KeyPress(object sender, KeyEventArgs e) { var textBox = (TextBox)sender; errorReportingLabel.Text = ""; if (e.Modifiers == Keys.Shift && e.KeyCode == Keys.Up) { if (_gAdSpecialIndex == -1) { textBox.AutoCompleteCustomSource = _AdSpecialList; errorReportingLabel.Text = "Auto complete mode changed to Ad Special."; } else { errorReportingLabel.Text = "An Ad Special row already exists, auto complete mode\n can not be changed."; } } else if (e.Modifiers == Keys.Shift && e.KeyCode == Keys.Down) { textBox.AutoCompleteCustomSource = _CustomAdItemCollection; errorReportingLabel.Text = "Auto complete mode changed to Ad Items."; } e.Handled = false; } /// /// Event Used: RowValidating /// /// /// /// private void UpdateInventoryActualSalesDataGridView(object sender, DataGridViewCellCancelEventArgs e) { //IF the current row is a new then simply return, we don't want to copy a new row over. if (projectionsDataGridView.Rows[e.RowIndex].IsNewRow) { return; } //IF the current row's Ad Item cell (column 0) is not empty then... if (projectionsDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString() != "") { var parser = new RowParser(); var rowContents = new string[11]; //Check to make sure the user didn't simply leave a row that already exists. if (projectionsDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString() == actualSalesDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString()) { return; } //Next check to see if the user changed the ad item is the corresponding row. if (projectionsDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString() != actualSalesDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString()) { if (projectionsDataGridView.RowCount == actualSalesDataGridView.RowCount) { string adItemText = projectionsDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString(); actualSalesDataGridView.Rows[e.RowIndex].Cells[0].Value = adItemText; actualSalesDataGridView.RefreshEdit(); //Remove the last ad item from the UsedAdItem array, the new one will be added in the OnRowLeave event handler. if (_gAdSpecialIndex == -1 || e.RowIndex < _gAdSpecialIndex) { _gUsedAdItems.RemoveAll(I => I.Equals(_gLastAdItemEntered + ":1", StringComparison.OrdinalIgnoreCase)); } else { _gUsedAdItems.RemoveAll(I => I.Equals(_gLastAdItemEntered + ":2", StringComparison.OrdinalIgnoreCase)); } return; } } _gLastAdItemEntered = projectionsDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString(); //IF the current row is either a MemberRow OR an AdSpecialRow then only add the item in the first cell, place holder values are not needed. if (parser.GetRowAttribute(projectionsDataGridView.Rows[e.RowIndex]) == RowParser.RowAttribute.MemberRow || parser.GetRowAttribute(projectionsDataGridView.Rows[e.RowIndex]) == RowParser.RowAttribute.AdSpecialRow) { rowContents[0] = projectionsDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString(); actualSalesDataGridView.Rows.Add(rowContents); PaintRowGroups(actualSalesDataGridView); return; } //Spin through the DataGridViewCells in the row and add their contents to an array. for (int i = 0; i < 11; i++) { //Grab the Ad Item in the first cell and add it into the array. if (i == 0) { rowContents[0] = projectionsDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString(); } //Index for the Sale Price cell. else if (i == 6) { //IF the Sale Price cell is empty then place 0.00 into the array as a place holder value (assuming this row is a HeaderRow). if (projectionsDataGridView.Rows[e.RowIndex].Cells[2].EditedFormattedValue.ToString() == "") { rowContents[6] = "0.00"; } //ELSE place the value from the Projections table into the array, since Sale Price can be determined before actual data is used. else { rowContents[6] = projectionsDataGridView.Rows[e.RowIndex].Cells[2].EditedFormattedValue.ToString(); } } //Index for the Cost cell. else if (i == 8) { //IF the Cost cell is empty then place 0.00 into the array as a place holder value (assuming this row is a HeaderRow). if (projectionsDataGridView.Rows[e.RowIndex].Cells[4].EditedFormattedValue.ToString() == "") { rowContents[8] = "0.00"; } //ELSE place the value from the Projections table into the array, since Cost can be determined before actual data is used. else { rowContents[8] = projectionsDataGridView.Rows[e.RowIndex].Cells[4].EditedFormattedValue.ToString(); } } else { //Add a place holder value for the cells that aren't Sale Price or Cost. rowContents[i] = "0"; } } actualSalesDataGridView.Rows.Add(rowContents); } //ELSE IF the Ad Item cell is empty, then throw an error and inform the user that there must be an Ad Item specified. else { MessageBox.Show("An Ad Item is required.", "Invalid Ad Item"); projectionsDataGridView.Rows[e.RowIndex].Cells[0].Selected = true; e.Cancel = true; } } /// /// Event Used: RowValidating /// /// /// /// private void UpdateProjectionsDataGridView(object sender, DataGridViewCellCancelEventArgs e) { if (actualSalesDataGridView.Rows[e.RowIndex].IsNewRow) { return; } if (actualSalesDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString() != "") { var parser = new RowParser(); object[] rowContents = new object[11]; //Check to make sure the user didn't simply leave a row that already exists. if (projectionsDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString() == actualSalesDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString()) { return; } //Next check to see if the user changed the ad item is the corresponding row. if (projectionsDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString() != actualSalesDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString()) { if (actualSalesDataGridView.RowCount == projectionsDataGridView.RowCount) { var adItemText = actualSalesDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString(); projectionsDataGridView.Rows[e.RowIndex].Cells[0].Value = adItemText; projectionsDataGridView.RefreshEdit(); //Remove the last ad item from the UsedAdItem array, the new one will be added in the OnRowLeave event handler. if (_gAdSpecialIndex == -1 || e.RowIndex < _gAdSpecialIndex) { _gUsedAdItems.RemoveAll(I => I.Equals(_gLastAdItemEntered + ":1", StringComparison.OrdinalIgnoreCase)); } else { _gUsedAdItems.RemoveAll(I => I.Equals(_gLastAdItemEntered + ":2", StringComparison.OrdinalIgnoreCase)); } return; } } _gLastAdItemEntered = actualSalesDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString(); //IF the current row is either a MemberRow OR an AdSpecialRow then only ad the item in the first cell, place holder values are not needed. if (parser.GetRowAttribute(actualSalesDataGridView.Rows[e.RowIndex]) == RowParser.RowAttribute.MemberRow || parser.GetRowAttribute(actualSalesDataGridView.Rows[e.RowIndex]) == RowParser.RowAttribute.AdSpecialRow) { rowContents[0] = actualSalesDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString(); projectionsDataGridView.Rows.Add(rowContents); PaintRowGroups(projectionsDataGridView); return; } //Spin through the DataGridViewCells in the row and add their contents to an array. for (var i = 0; i < 11; i++) { //Grab the Ad Item in the first cell and add it into the array. if (i == 0) { rowContents[0] = actualSalesDataGridView.Rows[e.RowIndex].Cells[0].EditedFormattedValue.ToString(); } //Index for the Sale Price cell. else if (i == 6) { //IF the Sale Price cell is empty then place 0.00 into the array as a place holder value (assuming this row is a HeaderRow). if (actualSalesDataGridView.Rows[e.RowIndex].Cells[6].EditedFormattedValue.ToString() == "") { rowContents[2] = ""; } //ELSE place the value from the Projections table into the array, since Sale Price can be determined before actual data is used. else { rowContents[2] = actualSalesDataGridView.Rows[e.RowIndex].Cells[6].EditedFormattedValue.ToString(); } } //Index for the Cost cell. else if (i == 8) { //IF the Cost cell is empty then place 0.00 into the array as a place holder value (assuming this row is a HeaderRow). if (actualSalesDataGridView.Rows[e.RowIndex].Cells[8].EditedFormattedValue.ToString() == "") { rowContents[4] = ""; } //ELSE place the value from the Projections table into the array, since Cost can be determined before actual data is used. else { rowContents[4] = actualSalesDataGridView.Rows[e.RowIndex].Cells[8].EditedFormattedValue.ToString(); } } else { //Add a place holder value for the cells that aren't Sale Price or Cost. rowContents[i] = ""; } } projectionsDataGridView.Rows.Add(rowContents); } else { MessageBox.Show("An Ad Item is required.", "Invalid Ad Item"); actualSalesDataGridView.Rows[e.RowIndex].Cells[0].Selected = true; e.Cancel = true; } } /// /// Event Used: CellValidating /// /// /// /// private void SupplierOnCellValidating(object sender, DataGridViewCellValidatingEventArgs e) { var dataGridView = ((DataGridView) sender); //IF the row that fires the event is a new row, then return. Validation is not required on a new row. if(dataGridView.Rows[e.RowIndex].IsNewRow) return; if (dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString() == "") return; if (e.ColumnIndex == 0) { var input = new DateTime(); if (!DateTime.TryParse(dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString(), out input)) { MessageBox.Show("You must enter a valid date with the format MM/DD/YYYY.", "Invalid Date"); e.Cancel = true; return; } dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = input.ToString("MM/dd/yyyy"); dataGridView.RefreshEdit(); } if (e.ColumnIndex == 1) { var input = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString(); TextInfo textInfo = new CultureInfo("en-US", false).TextInfo; dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = textInfo.ToTitleCase(input); dataGridView.RefreshEdit(); } if (e.ColumnIndex == 3 || e.ColumnIndex == 4) { double input = 0; if ( !Double.TryParse( dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString(), out input)) { MessageBox.Show("Only numbers may be entered in this column.", "Non Numeric Value"); e.Cancel = true; return; } dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = Math.Round(input, 2).ToString("N", new CultureInfo("en-US")); dataGridView.RefreshEdit(); } } /// /// Event Used: EditingControlShowing /// /// /// /// private void DisplaySupplierNameAutoComplete(object sender, DataGridViewEditingControlShowingEventArgs e) { var dataGridView = ((DataGridView)sender); var autoText = e.Control as TextBox; //IF the control is in fact an editing control and it is column two (2), then ... if (e.Control is DataGridViewTextBoxEditingControl && dataGridView.CurrentCell.ColumnIndex == 1) { autoText.AutoCompleteMode = AutoCompleteMode.Suggest; autoText.AutoCompleteSource = AutoCompleteSource.CustomSource; autoText.AutoCompleteCustomSource = _gSupplierCollection; } } /// /// Event Used: CellValidating /// Simply applies formatting to the Weekly Sales table hen the user clicks out of a cell. /// Also replaces null cells with zeros to have a value for the database to enter. /// /// /// private void FormatWeeklySalesOnCellValidating(object sender, DataGridViewCellValidatingEventArgs e) { if (weeklySalesDataGridView.Rows[0].Cells[e.ColumnIndex].EditedFormattedValue.ToString() == "0.00" || weeklySalesDataGridView.Rows[0].Cells[e.ColumnIndex].EditedFormattedValue.ToString() == "") { return; } double numberToFormat = 0; if (Double.TryParse(weeklySalesDataGridView.Rows[0].Cells[e.ColumnIndex].EditedFormattedValue.ToString(), out numberToFormat)) { weeklySalesDataGridView.Rows[0].Cells[e.ColumnIndex].Value = Math.Round(numberToFormat, 2).ToString("N", new CultureInfo("en-US")); weeklySalesDataGridView.RefreshEdit(); } else { MessageBox.Show("Only numeric values can be entered.", "Non Numeric Characters"); e.Cancel = true; } } //========================================= End DataGirdView event handlers ============================================================================= /// /// Paints rows according to their RowAttribute and detects whether or not they are part of a group. /// This function offers a faster method of determining all of this by starting at the row index that /// fired the row leave even. As opposed to the PaintRowGroups function which spins through all the /// DataGridView's rows. /// /// The starting index (the row that fired the RowLeave event) /// A reference to the DataGridView that fired the event. private void PaintRowsOnLeave(int startingIndex, DataGridView dataGridView) { var parser = new RowParser(); //If the current row is an Ad Special Row, the color code it and return as nothing further needs to be done. if (parser.GetRowAttribute(dataGridView.Rows[startingIndex]) != RowParser.RowAttribute.AdSpecialRow) ///TODo: check { _gAdSpecialIndex = startingIndex; dataGridView.Rows[startingIndex].DefaultCellStyle.BackColor = Color.Silver; return; } //Spin through the dataGridView rows starting at the row that fired the event. for (var i = startingIndex; i < (dataGridView.RowCount - 1); i++) { //Get the status of the current row. var rowStatus = parser.GetRowAttribute(dataGridView.Rows[i]); //IF the current row is a header row... if (rowStatus == RowParser.RowAttribute.HeaderRow) { _gLastRowHeaderIndex = i; //Then check to see if the next row is a row header. rowStatus = parser.GetRowAttribute(dataGridView.Rows[i + 1]); //IF so, color code this row as White, since it is not a true group header. if (rowStatus != RowParser.RowAttribute.HeaderRow) { dataGridView.Rows[i].DefaultCellStyle.BackColor = Color.White; } //IF the current row is not the first row in the data grid (index zero)... if (i > 0) { //The start by checking the previous row's status. rowStatus = parser.GetRowAttribute(dataGridView.Rows[i - 1]); //IF the previous row is a header row OR if the previous row is index zero AND a member row, clear its coloring. if (rowStatus == RowParser.RowAttribute.HeaderRow || rowStatus == RowParser.RowAttribute.MemberRow && (i - 1) == 0) { dataGridView.Rows[i - 1].DefaultCellStyle.BackColor = Color.White; } //IF the previous row is a header row AND has color coding saying it is a group header, then clear its color and apply it to this row (i). else if (rowStatus == RowParser.RowAttribute.HeaderRow && dataGridView.Rows[i - 1].DefaultCellStyle.BackColor == Color.LightGray) { dataGridView.Rows[i - 1].DefaultCellStyle.BackColor = Color.White; dataGridView.Rows[i].DefaultCellStyle.BackColor = Color.LightGray; } //IF previous row is Incomplete, then call the stable PaintRowGroups function. else if (rowStatus == RowParser.RowAttribute.IncompleteRow) { PaintRowGroups(dataGridView); } } } else if (rowStatus == RowParser.RowAttribute.MemberRow) { if (i > 0) { //Check the previous row. rowStatus = parser.GetRowAttribute(dataGridView.Rows[i - 1]); //IF the previous row is a member row AND is the first row in the data grid, then remove the coloring for it and the current row (i). if (rowStatus == RowParser.RowAttribute.MemberRow && (i - 1) == 0) { dataGridView.Rows[i - 1].DefaultCellStyle.BackColor = Color.White; dataGridView.Rows[i].DefaultCellStyle.BackColor = Color.White; } //IF the previous row is a member row AND it also has color coding suggesting that it is a member of a group, then add the current row (i) as well. else if (rowStatus == RowParser.RowAttribute.MemberRow && dataGridView.Rows[i - 1].DefaultCellStyle.BackColor == Color.LightBlue) { dataGridView.Rows[i].DefaultCellStyle.BackColor = Color.LightBlue; } //IF the previous row is simply a member row with no coloring at all, then remove the coloring from the current row (i). else if (rowStatus == RowParser.RowAttribute.MemberRow || rowStatus == RowParser.RowAttribute.AdSpecialRow) { dataGridView.Rows[i].DefaultCellStyle.BackColor = Color.White; } //IF the previous row is a header row, then color it as a group header and color the current row as a member of said group. else if (rowStatus == RowParser.RowAttribute.HeaderRow) { dataGridView.Rows[i - 1].DefaultCellStyle.BackColor = Color.LightGray; dataGridView.Rows[i].DefaultCellStyle.BackColor = Color.LightBlue; } //IF the previous row is incomplete, then call the stable PaintRowGroups function. else if (rowStatus == RowParser.RowAttribute.IncompleteRow) { PaintRowGroups(dataGridView); } } //ELSE the current row is the first row in the data grid, therefore it can't be a member row so remove all coloring. else { dataGridView.Rows[0].DefaultCellStyle.BackColor = Color.White; } } } } private void PaintRowGroups(DataGridView dataGridView) { var parser = new RowParser(); var statusReport = ""; var incompleteRowsFound = 0; var lastHeaderIndex = -1; var i = 0; var groupCount = 0; foreach (DataGridViewRow row in dataGridView.Rows) { //Get the current row's status. var rowType = parser.GetRowAttribute(row); //If the current row is not a group header, the first row in the grid, or a new row and in fact a member row... if (i != 0 && rowType == RowParser.RowAttribute.MemberRow && !row.IsNewRow && rowType != RowParser.RowAttribute.IncompleteRow) { //Remove all coloring on the current row. dataGridView.Rows[i].DefaultCellStyle.BackColor = Color.White; //Check to make sure the numbers are within bounds, errors occurs when an incomplete row is found at index zero (0), and the current row is one (1). if ((i - (1 + incompleteRowsFound)) > 0) { //Check to see if the previous row is a header row by subtracting the number of rows that are (incomplete + 1) from the total number of rows (i). //Adding one (1) to the incomplete count allows for checking the row right before the first incomplete row found so far to see if it's a header row. if (parser.GetRowAttribute(dataGridView.Rows[i - (1 + incompleteRowsFound)]) == RowParser.RowAttribute.HeaderRow) { row.DefaultCellStyle.BackColor = Color.LightBlue; //Group member dataGridView.Rows[lastHeaderIndex].DefaultCellStyle.BackColor = Color.LightGray; //Group header groupCount++; statusReport += $"\nGroup {groupCount} created with the header row {(i - incompleteRowsFound)} and the following row members: {(i + 1)} "; } //Else if a header row was not found from the previous operation but a header row is set, then its safe to assume that this row can be a member. else if (lastHeaderIndex >= 0) { //Check to make sure that the last header index is underneath the Ad Special Row OR that the current row (i) is before the Ad Special Index. if (lastHeaderIndex > _gAdSpecialIndex || i < _gAdSpecialIndex) { //Assume that the current row is a member of that group header and color it as such. row.DefaultCellStyle.BackColor = Color.LightBlue; statusReport += String.Format(" {0} ", (i + 1)); } } } } //If the current row is a potential group header AND the next row is as well remove the coloring from the current row, no need for checks. else if (rowType == RowParser.RowAttribute.HeaderRow && parser.GetRowAttribute(dataGridView.Rows[i + 1]) == RowParser.RowAttribute.HeaderRow) { dataGridView.Rows[i].DefaultCellStyle.BackColor = Color.White; } //Check to see if this row is the first row, a header index row, AND the next row is a MemberRow. else if (rowType == RowParser.RowAttribute.HeaderRow && parser.GetRowAttribute(dataGridView.Rows[i + 1]) == RowParser.RowAttribute.MemberRow && i == 0) { //IF so, set the last header index, and color code of this row along with the next row which is a MemberRow. lastHeaderIndex = 0; dataGridView.Rows[0].DefaultCellStyle.BackColor = Color.LightGray; dataGridView.Rows[i + 1].DefaultCellStyle.BackColor = Color.LightBlue; statusReport += $"Group {groupCount} created with the header row 1 and the following row member(s): {(i + 2)}"; } //Check to see if this row is a group header. else if (rowType == RowParser.RowAttribute.HeaderRow) { //If so, reset the incomplete rows found count, set the lastHeaderIndex to this row's index (i) and change it's color to white. incompleteRowsFound = 0; lastHeaderIndex = i; dataGridView.Rows[i].DefaultCellStyle.BackColor = Color.White; } //If the current row is the first row in the grid AND is not a group header then remove all color from it, since its not allowed to be a header or a member. else if (i == 0 && rowType == RowParser.RowAttribute.MemberRow) { dataGridView.Rows[i].DefaultCellStyle.BackColor = Color.White; } //Mark an incomplete row to determine whether or not we found one and remove any coloring it may have, incomplete rows are not allowed to be members or headers. if (rowType == RowParser.RowAttribute.IncompleteRow) { incompleteRowsFound++; dataGridView.Rows[i].DefaultCellStyle.BackColor = Color.White; } i++; }//end for-each dataGridView.Refresh(); _gLogConsole.WriteToLog(FrmLogConsole.Level.Debug, statusReport); }//End PaintRowGroups /// /// /// private void ConstructDataGridViews() { //Arrays containing the (name)s of the columns to be displayed string[] projectionsColumns = { "AdItem", "PrSold", "PrSalePrice", "PrTotalSales", "PrCost", "PrProfitReturn", "PrTotalProfitReturn" }; string[] inventoryActualSalesColumns = { "AdItem", "InvBeginingInventory", "InvReceived", "InvTotal", "InvEndingInventory", "AcSold", "AcSalePrice", "AcTotalSales", "AcCost", "AcProfitReturn", "AcTotalProfitReturn" }; string[] invoicesColumns = { "InvoiceDate", "Supplier", "InvoiceNumber", "InvoiceNetAmountAtCost", "InvoiceNetAmount", "InvoiceNote" }; string[] weeklySalesColumns = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "TotalSales" }; //Arrays containing the header text of the columns string[] projectionsColumnHeaderText = { "Ad Item", "Sold", "Sale Price", "Total Sales", "Cost", "Profit Return", "Total Profit Returned" }; string[] inventoryActualHeaderText = { "Ad Items", "Beginning Inventory", "Received", "Total", "Ending Inventory", "Sold", "Sale Price", "Total Sales", "Cost", "Profit Return", "Total Profit Return" }; string[] invoicesHeaderText = { "Invoice Date", "Supplier", "Invoice Number", "Net Amount of Invoices at Cost", "Net Amount of Invoices Extended Retail", "Invoice Notes" }; string[] weeklySalesHeaderText = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday", "Total Sales" }; //Index variable int i = 0; foreach (var columnName in projectionsColumns) { var column = new DataGridViewTextBoxColumn { Name = columnName, HeaderText = projectionsColumnHeaderText[i], SortMode = DataGridViewColumnSortMode.NotSortable, MaxInputLength = 50 }; projectionsDataGridView.Columns.Add(column); i++; } i = 0; foreach (var columnName in inventoryActualSalesColumns) { var column = new DataGridViewTextBoxColumn { Name = columnName, HeaderText = inventoryActualHeaderText[i], SortMode = DataGridViewColumnSortMode.NotSortable, MaxInputLength = 50 }; actualSalesDataGridView.Columns.Add(column); i++; } i = 0; foreach (string columnName in invoicesColumns) { var column = new DataGridViewTextBoxColumn { Name = columnName, HeaderText = invoicesHeaderText[i], SortMode = DataGridViewColumnSortMode.NotSortable }; suppliersDataGridView.Columns.Add(column); i++; } i = 0; foreach (string columnName in weeklySalesColumns) { var column = new DataGridViewTextBoxColumn { Name = columnName, HeaderText = weeklySalesHeaderText[i], SortMode = DataGridViewColumnSortMode.NotSortable, ValueType = typeof (string), DefaultCellStyle = {Format = "n2"} }; weeklySalesDataGridView.Columns.Add(column); i++; } //Only one row exists in the Weekly Sales DataGridView. weeklySalesDataGridView.Rows.Add(0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00, 0.00); weeklySalesDataGridView.Columns[0].SortMode = DataGridViewColumnSortMode.NotSortable; }//End ConstructForms /// /// /// /// /// private void addRecordsButton_Click(object sender, EventArgs e) { //IF the tables don't line up, then the data in them is no good, so return. if (projectionsDataGridView.RowCount != actualSalesDataGridView.RowCount) { MessageBox.Show("The Projections and Inventory / Actual tables must have the same number of rows.", "Invalid Row Count"); return; } //Initialize the database reader and writer classes. //var databaseTracker = new DatabaseTracker(); //var databaseReader = new DatabaseReader(); //var databaseWriter = new DatabaseWriter(databaseTracker.DatabaseConnectionString); if (weekEndingDateMaskedTextBox.MaskCompleted) { //if (databaseReader.RetrieveDateIdByDateString(weekEndingDateMaskedTextBox.Text, databaseTracker.DatabaseConnectionString) == 0) //{ // //Assume the date is correct and add it to the database. // //TODO: Check the date vs the last date entered (obtained by sorting dates) and check to see if the two are seven (7) or more days apart. // if (!databaseWriter.InsertIntoWeekEnding(weekEndingDateMaskedTextBox.Text)) // { // //IF the date failed to add for whatever reason, inform the user and break. // MessageBox.Show("An error has occurred attempting to write the new date into the database.", "Insert Error"); // return; // } //} } else { MessageBox.Show("You must have a valid date.", "Invalid Date Format"); return; } //Most recent date ID, the hell was I thinking.. //var dateIdString = databaseReader.RetrieveDateIdByDateString(weekEndingDateMaskedTextBox.Text, databaseTracker.DatabaseConnectionString); //var commentsText = commentsTextBox.Text; //if (Regex.Replace(commentsText, @"\s+", "") != "") //{ // databaseWriter.RedundantlessInsertIntoComments(commentsTextBox.Text, dateIdString.ToString()); //} //Send the table's data to their respective functions. _gLogConsole.WriteToLog(FrmLogConsole.Level.Info, "Added the following rows to the APC table:"); //var rowsEffected = BuildAPCAndSendToDatabase(dateIdString.ToString()); //foreach (var i in rowsEffected) //{ // _gLogConsole.WriteToLog(FrmLogConsole.Level.Info, (i + 1).ToString()); //} //_gLogConsole.WriteToLog(FrmLogConsole.Level.Info, "Added the following rows to the Invoices table:"); //rowsEffected = BuildInvoiceTableAndSendToDatabase(); //foreach (int i in rowsEffected) //{ // _gLogConsole.WriteToLog(FrmLogConsole.Level.Info, (i + 1).ToString()); //} //if (InsertWeeklySalesIntoDatabase()) //{ // _gLogConsole.WriteToLog(FrmLogConsole.Level.Info, "Successfully added weekly sales to the database."); //} //else //{ // _gLogConsole.WriteToLog(FrmLogConsole.Level.Info, "Failed to add weekly sales to the database."); //} } private void closeFileMainMenu_Click(object sender, EventArgs e) { Close(); } private void clearFormFileMainMenu_Click(object sender, EventArgs e) { projectionsDataGridView.Rows.Clear(); actualSalesDataGridView.Rows.Clear(); suppliersDataGridView.Rows.Clear(); var i = 0; foreach (var column in weeklySalesDataGridView.Columns) { weeklySalesDataGridView.Rows[0].Cells[i].Value = ""; i++; } weeklySalesDataGridView.RefreshEdit(); _gAdSpecialIndex = -1; _gUsedAdItems.Clear(); _gLastRowHeaderIndex = -1; _gLastAdItemEntered = ""; weekEndingDateMaskedTextBox.Clear(); commentsTextBox.Clear(); } } }