Set up Invoice DataGridView event handlers to validate user input and provide basic formatting for the contents of the cells. Updated the week ending masked text box to get a parsed DateTime value, just to make it look pretty.

This commit is contained in:
2016-11-08 02:24:58 -06:00
parent f60cc5ab8b
commit 8e140a7131
9 changed files with 243 additions and 45 deletions
@@ -288,6 +288,18 @@ namespace AdvertsingProfitControl
IsInDatabase = 11
}
public enum InvoiceTableColumns
{
Id = 0,
InvoiceDate = 1,
Supplier = 2,
InvoiceNumber = 3,
InvoiceNetAmountAtCost = 4,
InvoiceNetAmount = 5,
InvoiceNote = 6,
IsDirty = 7
}
public enum TrimmingOperationResult
{
FailedToTrim = 0,
+215 -29
View File
@@ -14,14 +14,13 @@ namespace AdvertsingProfitControl
{
private static readonly FrmLogConsole LogConsole = FrmLogConsole.GetStaticInstance;
//Create an array that contains all the ad items from the database.
//private read only Dictionary<int, string> _adItemCollectionDictionary;
private readonly List<string> _adItemCollection;
//This object contains all the unused ad items.
private AutoCompleteStringCollection _trimmedAdItemCollection = new AutoCompleteStringCollection();
//Contains all the ad specials that are in the database (i.e. "Daily Coupons").
private readonly AutoCompleteStringCollection _adSpecialList;
//This object contains all the suppliers that were found in the database.
private AutoCompleteStringCollection _supplierCollection;
private readonly AutoCompleteStringCollection _supplierCollection;
//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.
//The structure of the used ad item list is as follows:
@@ -32,8 +31,6 @@ namespace AdvertsingProfitControl
private string _beginningCellValue = "";
//Flag showing whether or not the AdSpecialRow has been made in this session.
private int _adSpecialIndex = -1;
//Set the starting value for temporary IDs for ad items that have yet to be added to the database.
//private int _temporaryKey;
private readonly AdvertisingProfitControlTableHelper _tableHelperFunctions = new AdvertisingProfitControlTableHelper();
//Set flags to indicate whether or not a DataGridView needs to be painted.
private bool _projectionsRequirePainting;
@@ -97,9 +94,193 @@ namespace AdvertsingProfitControl
mainTabControl.SelectedIndexChanged += PaintDataGridViewOnTabPageChange;
//After all events have been set, construct the DataGridVeiws for use.
ConstructApcDataGridViews();
//Set-up events for the Invoice table.
invoicesDataGridView.CellEnter += StoreBeginningCellValue;
//Validate that the row the user is trying to leave is legal (has at least an ad item entered) and prevent the user from leaving the row is its not.
invoicesDataGridView.RowValidating += ValidateInvoiceRow;
//Validate, clean and format the contents of the cell that fires the cell validating event.
invoicesDataGridView.CellValidating += ValidateInvoicesCellContents;
//Grab the underlying text box object in the ad item cell, and build an auto complete list for the user.
invoicesDataGridView.EditingControlShowing += DisplaySupplierAutoComleteOnEditingShadowControl;
//Finally build the last DataGridView for the form.
ConstructInvoicesDataGridView();//No weekly sales table is nice.
}
#region Invoice Table Events
/// <summary>
/// Event Used: RowValidating
/// Validates that the row has required information, namely an invoice date, number and supplier.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ValidateInvoiceRow(object sender, DataGridViewCellCancelEventArgs e)
{
var dataGridView = (DataGridView) sender;
if (dataGridView.Rows[e.RowIndex].IsNewRow) return;
//Check to make sure the Invoice Date, Invoice Number and the Supplier values are set.
if (dataGridView.Rows[e.RowIndex].Cells[(int) InvoiceTableColumns.InvoiceDate].EditedFormattedValue.ToString() == "")
{
MessageBox.Show(@"An invoice date must be specified.", @"Invalid Invoice Date", MessageBoxButtons.OK, MessageBoxIcon.Error);
e.Cancel = true;
dataGridView.CurrentCell = dataGridView.Rows[e.RowIndex].Cells[(int)InvoiceTableColumns.InvoiceDate];
return;
}
if (dataGridView.Rows[e.RowIndex].Cells[(int)InvoiceTableColumns.Supplier].EditedFormattedValue.ToString() == "")
{
MessageBox.Show(@"A supplier must be specified.", @"Invalid Supplier", MessageBoxButtons.OK, MessageBoxIcon.Error);
e.Cancel = true;
dataGridView.CurrentCell = dataGridView.Rows[e.RowIndex].Cells[(int) InvoiceTableColumns.Supplier];
return;
}
if (dataGridView.Rows[e.RowIndex].Cells[(int) InvoiceTableColumns.InvoiceNumber].EditedFormattedValue.ToString() == "")
{
MessageBox.Show(@"An invoice number must be specified.", @"Invalid Invoice Number", MessageBoxButtons.OK, MessageBoxIcon.Error);
dataGridView.CurrentCell = dataGridView.Rows[e.RowIndex].Cells[(int)InvoiceTableColumns.InvoiceNumber];
e.Cancel = true;
}
}
/// <summary>
/// Event Used: CellValidating
/// Verifies the contents of the invoice table's cells. Also applies formating where needed.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ValidateInvoicesCellContents(object sender, DataGridViewCellValidatingEventArgs e)
{
//Grab the DataGirdView that fired the event and make it into a local variable.
var dataGridView = (DataGridView)sender;
var userInput = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString().Trim();
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;
}
//Mark the row as dirty assuming the user made changes
if (userInput != _beginningCellValue)
{
dataGridView.Rows[e.RowIndex].Cells[(int) InvoiceTableColumns.IsDirty].Value = true;
}
else
{
return;
}
//Check to see if we're in the invoice date column make sure the date is valid.
switch (e.ColumnIndex)
{
case (int) InvoiceTableColumns.InvoiceDate:
//Clear any error text a cell has for this column.
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "";
if (userInput != "")
{
DateTime date;
//Try parsing the date to make sure its valid, otherwise clear it from the cell and inform the user.
if (DateTime.TryParse(userInput, out date))
{
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = date.ToString("MM/dd/yyyy");
}
else
{
MessageBox.Show(@"The date '" + userInput + @"' is not a valid date.", @"Invalid Date", MessageBoxButtons.OK, MessageBoxIcon.Error);
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "Invoice Date Must be in a Valid Format";
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = "";
}
}
else
{
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = "";
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "An Invoice Date is Required";
}
break;
case (int) InvoiceTableColumns.InvoiceNumber:
//Clear any error text a cell has for this column.
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "";
if (userInput != "")
{
long parsedNumber;
if (long.TryParse(userInput, out parsedNumber))
{
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = parsedNumber;
}
else
{
MessageBox.Show(@"The invoice number must be a numeric value.", @"Non Numeric Invoice Number", MessageBoxButtons.OK, MessageBoxIcon.Error);
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = "";
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "Invoice Number Must be Numeric";
}
}
else
{
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = "";
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "An Invoice Number is Required";
}
break;
case (int) InvoiceTableColumns.Supplier:
//Clear any error text a cell has for this column.
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "";
if (userInput != "")
{
//TODO: Create a custom engine to do this.
//Pretty up the entered text since there is something here.
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = textInfo.ToTitleCase(userInput);
}
else
{
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = "";
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "A Supplier is Required";
}
break;
default:
//Should only process the InvoiceNetAmountAtCost and InvoiceNetAmount columns.
if (e.ColumnIndex != (int) InvoiceTableColumns.Id &&
e.ColumnIndex < (int) InvoiceTableColumns.InvoiceNote)
{
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "";
//Now check to make sure the user input isn't null
//Math.Round(parsedNumber, 2).ToString("N", new CultureInfo("en-US"));
if (userInput != "")
{
double parsedNumber;
if (double.TryParse(userInput, out parsedNumber))
{
//Since the input is a number format it to show the cents and display it.
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = Math.Round(parsedNumber, 2).ToString("N", new CultureInfo("en-US"));
}
else
{
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value = "";
dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].ErrorText = "Only Numeric Values Allowed.";
}
}
}
break;
}
dataGridView.RefreshEdit();
}
/// <summary>
/// Event Used: EditingShadowControlShowing
/// Adds an auto-complete list of suppliers to the Suppliers cell.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void DisplaySupplierAutoComleteOnEditingShadowControl(object sender, DataGridViewEditingControlShowingEventArgs e)
{
var dataGridView = (DataGridView) sender;
var autoText = e.Control as TextBox;
if (autoText == null) return;
if (!(e.Control is DataGridViewTextBoxEditingControl) || dataGridView.CurrentCell.ColumnIndex != (int) InvoiceTableColumns.Supplier) return;
autoText.AutoCompleteMode = AutoCompleteMode.Suggest;
autoText.AutoCompleteSource = AutoCompleteSource.CustomSource;
autoText.AutoCompleteCustomSource = _supplierCollection;
}
#endregion
private void PaintDataGridViewOnTabPageChange(object sender, EventArgs e)
{
var helper = new AdvertisingProfitControlTableHelper();
@@ -398,7 +579,7 @@ namespace AdvertsingProfitControl
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 dataGridView = (DataGridView)sender;
var userInput = dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].EditedFormattedValue.ToString();
//TODO: Write a custom parsing engine for detecting when bins are entered.
var textInfo = new CultureInfo("en-US", false).TextInfo;
@@ -1455,26 +1636,39 @@ namespace AdvertsingProfitControl
/// </summary>
private void ConstructInvoicesDataGridView()
{
string[] invoicesColumnNames = { "InvoiceDate", "Supplier", "InvoiceNumber", "InvoiceNetAmountAtCost", "InvoiceNetAmount", "InvoiceNote", "IsDirty", "IsInDatabase"};
string[] invoicesColumnNames = { "ID", "InvoiceDate", "Supplier", "InvoiceNumber", "InvoiceNetAmountAtCost", "InvoiceNetAmount", "InvoiceNote", "IsDirty"};
foreach (var name in invoicesColumnNames)
{
var column = new DataGridViewColumn { Name = name };
if (!name.StartsWith("Is"))
{
column.HeaderText = TextFormat.AddSpacesToSentence(name, false);
column.ValueType = typeof(string);
var column = new DataGridViewTextBoxColumn
{
Name = name,
HeaderText = TextFormat.AddSpacesToSentence(name, false),
ValueType = typeof(string),
SortMode = DataGridViewColumnSortMode.NotSortable,
MaxInputLength = 20
};
if (name.Contains("ID"))
{
//column.Visible = false;
}
invoicesDataGridView.Columns.Add(column);
}
else
{
column.HeaderText = TextFormat.AddSpacesToSentence(name, false);
column.Visible = false;
column.ValueType = typeof(bool);
}
column.CellTemplate = new DataGridViewTextBoxCell();
var column = new DataGridViewCheckBoxColumn
{
Name = name,
ValueType = typeof(bool),
//Visible = false,
SortMode = DataGridViewColumnSortMode.NotSortable
};
invoicesDataGridView.Columns.Add(column);
}
}
}
#endregion
@@ -1530,31 +1724,23 @@ namespace AdvertsingProfitControl
private void UpdateCalendarOnFocusLost(object sender, EventArgs e)
{
//Replace any white space with zeros to pad out the mask.
weekEndingMaskedTextBox.Text = weekEndingMaskedTextBox.Text.Replace(' ', '0');
//Check to see if the mask is completed, otherwise clear it.
if (weekEndingMaskedTextBox.MaskCompleted)
{
weekEndingMaskedTextBox.Text = weekEndingMaskedTextBox.Text.Replace("/", "");
DateTime date;
//Try parsing the contents of the masked text box to see if the date is valid.
if (DateTime.TryParse(weekEndingMaskedTextBox.Text, out date))
{
//Update the text box's text with a nicely formatted date.
weekEndingMaskedTextBox.Text = date.ToString("MM/dd/yyyy");
//If it is update the calendar with the manually entered date.
weekEndingMonthCalendar.SelectionStart = date;
}
else
{
//Otherwise throw an error to day that the date isn't valid and clear the text box.
MessageBox.Show(@"The date entered appears to be invalid", @"Invalid Date", MessageBoxButtons.OK,
MessageBoxIcon.Error);
MessageBox.Show(@"The date entered appears to be invalid.", @"Invalid Date", MessageBoxButtons.OK, MessageBoxIcon.Error);
weekEndingMaskedTextBox.Text = "";
}
}
else
{
weekEndingMaskedTextBox.Text = "";
}
}
#endregion
private void getCellValueDebugMainMenu_Click(object sender, EventArgs e)
@@ -1652,9 +1838,9 @@ namespace AdvertsingProfitControl
}
//Run the row parsing engine on all the APC tables.
//Create the cleaned table objects that will be sent to the database.
var trimmed = new DataTable();
var update = new DataTable();
var trimmedProjectionsTable = ConstructCleanedProjectionsTable(dateId, out trimmed, out update);
//var trimmed = new DataTable();
//var update = new DataTable();
//var trimmedProjectionsTable = ConstructCleanedProjectionsTable(dateId, out trimmed, out update);
//var trimmedInventoryTable = ConstructCleanedInventoryTable(dateId);
//var trimmedActualSalesTable = ConstructCleanedActualSalesTable(dateId);
//Create the transaction scope.
Binary file not shown.
@@ -14,7 +14,7 @@
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>a9nSyX771UnNpCxSLQTrqyr+/1DNpDIEZBXaQAVLi88=</dsig:DigestValue>
<dsig:DigestValue>LsVCFrHqz9eC+Xb4h5OB0HAtYPeUrflbVosVWeS6Y6M=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
@@ -43,14 +43,14 @@
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="AdvertsingProfitControl.exe" size="3511296">
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="AdvertsingProfitControl.exe" size="3517440">
<assemblyIdentity name="AdvertsingProfitControl" version="0.9.5.2" language="neutral" processorArchitecture="amd64" />
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>EvD+c0PqPuyMPwSjcVOB4gfL+Q/3iQ2v/e+IKDLio0Y=</dsig:DigestValue>
<dsig:DigestValue>iKpPfS5yNYsJ6mqWS0c0RqAtEX1hyz5JzaK7T5nObHU=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
@@ -14,7 +14,7 @@
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>a9nSyX771UnNpCxSLQTrqyr+/1DNpDIEZBXaQAVLi88=</dsig:DigestValue>
<dsig:DigestValue>LsVCFrHqz9eC+Xb4h5OB0HAtYPeUrflbVosVWeS6Y6M=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
@@ -43,14 +43,14 @@
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="AdvertsingProfitControl.exe" size="3511296">
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="AdvertsingProfitControl.exe" size="3517440">
<assemblyIdentity name="AdvertsingProfitControl" version="0.9.5.2" language="neutral" processorArchitecture="amd64" />
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>EvD+c0PqPuyMPwSjcVOB4gfL+Q/3iQ2v/e+IKDLio0Y=</dsig:DigestValue>
<dsig:DigestValue>iKpPfS5yNYsJ6mqWS0c0RqAtEX1hyz5JzaK7T5nObHU=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
@@ -14,7 +14,7 @@
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>a9nSyX771UnNpCxSLQTrqyr+/1DNpDIEZBXaQAVLi88=</dsig:DigestValue>
<dsig:DigestValue>LsVCFrHqz9eC+Xb4h5OB0HAtYPeUrflbVosVWeS6Y6M=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>
@@ -43,14 +43,14 @@
</dependentAssembly>
</dependency>
<dependency>
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="AdvertsingProfitControl.exe" size="3511296">
<dependentAssembly dependencyType="install" allowDelayedBinding="true" codebase="AdvertsingProfitControl.exe" size="3517440">
<assemblyIdentity name="AdvertsingProfitControl" version="0.9.5.2" language="neutral" processorArchitecture="amd64" />
<hash>
<dsig:Transforms>
<dsig:Transform Algorithm="urn:schemas-microsoft-com:HashTransforms.Identity" />
</dsig:Transforms>
<dsig:DigestMethod Algorithm="http://www.w3.org/2000/09/xmldsig#sha256" />
<dsig:DigestValue>EvD+c0PqPuyMPwSjcVOB4gfL+Q/3iQ2v/e+IKDLio0Y=</dsig:DigestValue>
<dsig:DigestValue>iKpPfS5yNYsJ6mqWS0c0RqAtEX1hyz5JzaK7T5nObHU=</dsig:DigestValue>
</hash>
</dependentAssembly>
</dependency>