diff --git a/C968Project/C968Project.csproj.user b/C968Project/C968Project.csproj.user index df91392..ad5bea3 100644 --- a/C968Project/C968Project.csproj.user +++ b/C968Project/C968Project.csproj.user @@ -1,5 +1,8 @@  + + <_LastSelectedProfileId>C:\Users\chris\Documents\school\csharp1\C968Project\C968Project\Properties\PublishProfiles\FolderProfile.pubxml + Form diff --git a/C968Project/Helpers.cs b/C968Project/Helpers.cs index 1e1d062..9d7531a 100644 --- a/C968Project/Helpers.cs +++ b/C968Project/Helpers.cs @@ -31,5 +31,44 @@ namespace C968Project return false; } + + public static void SearchDataGridView(DataGridView data, string searchValue) + { + // Search the datagridview items for text and then select the first occurence + data.CurrentCell = null; + + string search = searchValue; + + if (searchValue == string.Empty) + { + MessageBox.Show("Cant search an empty value", "", MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + if (data.Rows.Count == 0) + { + MessageBox.Show("Nothing to search for", "", MessageBoxButtons.OK, MessageBoxIcon.Information); + return; + } + + foreach (DataGridViewRow row in data.Rows) + { + foreach (DataGridViewCell cell in row.Cells) + { + if (cell.FormattedValue != null && cell.FormattedValue.ToString().ToLower().Contains(search.ToLower(), StringComparison.OrdinalIgnoreCase)) + { + data.CurrentCell = cell; + return; + } + } + } + + MessageBox.Show("No matching search results", "", MessageBoxButtons.OK, MessageBoxIcon.Information); + } + + public static void ShowErrorMessage(string message, string title = "", MessageBoxButtons buttons = MessageBoxButtons.OK) + { + MessageBox.Show(message, title, buttons, MessageBoxIcon.Error); + } } } diff --git a/C968Project/Program.cs b/C968Project/Program.cs index f406308..460bcf9 100644 --- a/C968Project/Program.cs +++ b/C968Project/Program.cs @@ -7,7 +7,7 @@ static class Program { public static Inventory Inventory = new(); - public static int PartIdCounter = 2; + public static int PartIdCounter = 1; public static int ProductIdCounter = 1; private static Part _testInhousePart = new Inhouse() @@ -33,7 +33,7 @@ static class Program private static Product _testProduct = new Product() { - Name = "Product", + Name = "One Product", InStock = 500, Max = 4000, Min = 2, @@ -41,19 +41,25 @@ static class Program ProductId = 0, }; - /// - /// The main entry point for the application. - /// + private static Product _testProduct2 = new Product() + { + Name = "Two Product", + InStock = 1, + Max = 1, + Min = 1, + Price = 1.40f, + ProductId = 1, + }; + [STAThread] static void Main() { Inventory.AddPart(_testOutsourcedPart); Inventory.AddPart(_testInhousePart); Inventory.AddProduct(_testProduct); + Inventory.AddProduct(_testProduct2); Inventory.Products[0].AddAssociatedPart(Inventory.Parts[0]); - // To customize application configuration such as set high DPI settings or default font, - // see https://aka.ms/applicationconfiguration. ApplicationConfiguration.Initialize(); Application.Run(new MainScreen()); } diff --git a/C968Project/Properties/PublishProfiles/FolderProfile.pubxml b/C968Project/Properties/PublishProfiles/FolderProfile.pubxml new file mode 100644 index 0000000..ba1c48f --- /dev/null +++ b/C968Project/Properties/PublishProfiles/FolderProfile.pubxml @@ -0,0 +1,11 @@ + + + + + Release + Any CPU + bin\Release\net9.0-windows\publish\ + FileSystem + <_TargetId>Folder + + \ No newline at end of file diff --git a/C968Project/Properties/PublishProfiles/FolderProfile.pubxml.user b/C968Project/Properties/PublishProfiles/FolderProfile.pubxml.user new file mode 100644 index 0000000..e787055 --- /dev/null +++ b/C968Project/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -0,0 +1,8 @@ + + + + + True|2025-05-16T03:22:13.0789367Z||; + + + \ No newline at end of file diff --git a/C968Project/Views/AddModifyPartScreen.Designer.cs b/C968Project/Views/AddModifyPartScreen.Designer.cs index c33be6d..f1bc8b0 100644 --- a/C968Project/Views/AddModifyPartScreen.Designer.cs +++ b/C968Project/Views/AddModifyPartScreen.Designer.cs @@ -118,7 +118,7 @@ nameTextBox.Name = "nameTextBox"; nameTextBox.Size = new Size(153, 23); nameTextBox.TabIndex = 4; - nameTextBox.Validating += nameTextBox_Validating; + nameTextBox.TextChanged += nameTextBox_TextChanged; // // inventoryLabel // @@ -135,7 +135,7 @@ inventoryTextBox.Name = "inventoryTextBox"; inventoryTextBox.Size = new Size(153, 23); inventoryTextBox.TabIndex = 6; - inventoryTextBox.Validating += inventoryTextBox_Validating; + inventoryTextBox.TextChanged += inventoryTextBox_TextChanged; // // priceCostLabel // @@ -152,7 +152,7 @@ priceCostTextBox.Name = "priceCostTextBox"; priceCostTextBox.Size = new Size(153, 23); priceCostTextBox.TabIndex = 8; - priceCostTextBox.Validating += priceCostTextBox_Validating; + priceCostTextBox.TextChanged += priceCostTextBox_TextChanged; // // machineCompanyLabel // @@ -169,7 +169,7 @@ machineCompanyTextBox.Name = "machineCompanyTextBox"; machineCompanyTextBox.Size = new Size(153, 23); machineCompanyTextBox.TabIndex = 10; - machineCompanyTextBox.Validating += machineCompanyTextBox_Validating; + machineCompanyTextBox.TextChanged += machineCompanyTextBox_TextChanged; // // label6 // @@ -186,7 +186,7 @@ maxTextBox.Name = "maxTextBox"; maxTextBox.Size = new Size(69, 23); maxTextBox.TabIndex = 12; - maxTextBox.Validating += maxTextBox_Validating; + maxTextBox.TextChanged += maxTextBox_TextChanged; // // label7 // @@ -203,7 +203,7 @@ minTextBox.Name = "minTextBox"; minTextBox.Size = new Size(69, 23); minTextBox.TabIndex = 14; - minTextBox.Validating += minTextBox_Validating; + minTextBox.TextChanged += minTextBox_TextChanged; // // saveButton // diff --git a/C968Project/Views/AddModifyPartScreen.cs b/C968Project/Views/AddModifyPartScreen.cs index 90ec46a..d5f65fc 100644 --- a/C968Project/Views/AddModifyPartScreen.cs +++ b/C968Project/Views/AddModifyPartScreen.cs @@ -38,16 +38,14 @@ namespace C968Project.Views { screenLabel.Text = "Add Part"; ChangeMode(Mode.INHOUSE); - ValidateInputs(); } else if (screenOption == ScreenOption.MODIFY) { screenLabel.Text = "Modify Part"; PopulatePartData(_selectedPart); - inHouseRadioButton.Enabled = false; - outsourcedRadioButton.Enabled = false; - ValidateInputs(); } + + ValidateInputs(true); } private void PopulatePartData(Part part) @@ -193,22 +191,35 @@ namespace C968Project.Views OUTSOURCED } - private bool ValidateInputs() + private bool ValidateInputs(bool initial = false) { - ValidateName(); - ValidateInventory(); - ValidatePrice(); - ValidateMax(); - ValidateMin(); - ValidateMachineOrCompany(); + bool valid = false; + string err = string.Empty; - return _isNameValid && _isInventoryValid && _isPriceValid && _isMaxValid && _isMinValid && _isMachineOrCompanyValid; + err += ValidateName(); + err += ValidateInventory(); + err += ValidatePrice(); + err += ValidateMax(); + err += ValidateMin(); + err += ValidateMachineOrCompany(); + + valid = _isNameValid && _isInventoryValid && _isPriceValid && _isMaxValid && _isMinValid && _isMachineOrCompanyValid; + + if (!valid && !initial) + { + Helpers.ShowErrorMessage(err, "Validation error"); + } + + return valid; } - private void ValidateName() + private string ValidateName() { + string err = string.Empty; + if (nameTextBox.Text == string.Empty) { + err = "Part must have a name\n"; errorProvider1.SetError(nameTextBox, "Please enter a part name"); _isNameValid = false; } @@ -219,15 +230,12 @@ namespace C968Project.Views } Helpers.SetTextBoxValidationState(nameTextBox, _isNameValid); + return err; } - private void nameTextBox_Validating(object sender, CancelEventArgs e) - { - ValidateName(); - } - - private void ValidateInventory() + private string ValidateInventory() { + string err = string.Empty; int inventory = 0; if (inventoryTextBox.Text != string.Empty && int.TryParse(inventoryTextBox.Text, out inventory)) @@ -236,11 +244,13 @@ namespace C968Project.Views { if (inventory > _validatedMax) { + err = $"Inventory must be less than Max: {_validatedMax}\n"; errorProvider1.SetError(inventoryTextBox, $"Must be less than Max: {_validatedMax}"); _isInventoryValid = false; } else if (inventory < _validatedMin) { + err = $"Inventory must be more than Min: {_validatedMin}\n"; errorProvider1.SetError(inventoryTextBox, $"Must be greater than Min: {_validatedMin}"); _isInventoryValid = false; } @@ -252,26 +262,25 @@ namespace C968Project.Views } else { + err = "Inventory can't be set without valid Min and Max values\n"; errorProvider1.SetError(inventoryTextBox, $"Min and Max values must be set"); _isInventoryValid = false; } } else { + err = "Inventory must be an integer value\n"; _isInventoryValid = false; errorProvider1.SetError(inventoryTextBox, "Field must contain an integer value"); } Helpers.SetTextBoxValidationState(inventoryTextBox, _isInventoryValid); + return err; } - private void inventoryTextBox_Validating(object sender, CancelEventArgs e) - { - ValidateInventory(); - } - - private void ValidatePrice() + private string ValidatePrice() { + string err = string.Empty; float price = 0f; if (priceCostTextBox.Text != string.Empty && float.TryParse(priceCostTextBox.Text, out price)) @@ -283,18 +292,16 @@ namespace C968Project.Views { _isPriceValid = false; errorProvider1.SetError(priceCostTextBox, "Field must contain a floating point number"); + err = "Price must be a decimal value\n"; } Helpers.SetTextBoxValidationState(priceCostTextBox, _isPriceValid); + return err; } - private void priceCostTextBox_Validating(object sender, CancelEventArgs e) - { - ValidatePrice(); - } - - private void ValidateMax() + private string ValidateMax() { + string err = string.Empty; int max = 0; if (maxTextBox.Text != string.Empty && int.TryParse(maxTextBox.Text, out max)) { @@ -306,19 +313,23 @@ namespace C968Project.Views { _isMaxValid = false; errorProvider1.SetError(maxTextBox, "Field must contain an integer value"); + err = "Max must be an integer value\n"; + } + + if (_isMinValid && _isMaxValid && _validatedMax < _validatedMin) + { + _isMaxValid = false; + err = $"Max cannot be less than Min: {_validatedMin}\n"; + errorProvider1.SetError(maxTextBox, $"Max cannot be less than Min: {_validatedMin}"); } ValidateInventory(); Helpers.SetTextBoxValidationState(maxTextBox, _isMaxValid); + return err; } - - private void maxTextBox_Validating(object sender, CancelEventArgs e) - { - ValidateMax(); - } - - private void ValidateMin() + private string ValidateMin() { + string err = string.Empty; int min = 0; if (minTextBox.Text != string.Empty && int.TryParse(minTextBox.Text, out min)) { @@ -330,19 +341,25 @@ namespace C968Project.Views { _isMinValid = false; errorProvider1.SetError(minTextBox, "Field must contain an integer value"); + err = "Min must be an integer value\n"; + } + + if (_isMinValid && _isMaxValid && _validatedMin > _validatedMax) + { + _isMinValid = false; + err = $"Min cannot be more than Max: {_validatedMax}\n"; + errorProvider1.SetError(maxTextBox, $"Min cannot be more than Max: {_validatedMax}"); } ValidateInventory(); Helpers.SetTextBoxValidationState(minTextBox, _isMinValid); + return err; } - private void minTextBox_Validating(object sender, CancelEventArgs e) + private string ValidateMachineOrCompany() { - ValidateMin(); - } + string err = string.Empty; - private void ValidateMachineOrCompany() - { if (machineCompanyTextBox.Text == string.Empty) { _isMachineOrCompanyValid = false; @@ -350,11 +367,13 @@ namespace C968Project.Views if (_mode is Mode.INHOUSE) { errorProvider1.SetError(machineCompanyTextBox, "Field must contain an integer value"); + err = "Machine ID must have an integer value\n"; } if (_mode is Mode.OUTSOURCED) { errorProvider1.SetError(machineCompanyTextBox, "Field must contain a value"); + err = "Company Name must have a value\n"; } } else @@ -371,6 +390,7 @@ namespace C968Project.Views { _isMachineOrCompanyValid = false; errorProvider1.SetError(machineCompanyTextBox, "Field must contain an integer value"); + err = "Machine ID must be an integer value\n"; } } @@ -385,11 +405,42 @@ namespace C968Project.Views } Helpers.SetTextBoxValidationState(machineCompanyTextBox, _isMachineOrCompanyValid); + return err; } private void machineCompanyTextBox_Validating(object sender, CancelEventArgs e) { ValidateMachineOrCompany(); } + + private void nameTextBox_TextChanged(object sender, EventArgs e) + { + ValidateName(); + } + + private void inventoryTextBox_TextChanged(object sender, EventArgs e) + { + ValidateInventory(); + } + + private void priceCostTextBox_TextChanged(object sender, EventArgs e) + { + ValidatePrice(); + } + + private void maxTextBox_TextChanged(object sender, EventArgs e) + { + ValidateMax(); + } + + private void minTextBox_TextChanged(object sender, EventArgs e) + { + ValidateMin(); + } + + private void machineCompanyTextBox_TextChanged(object sender, EventArgs e) + { + ValidateMachineOrCompany(); + } } } diff --git a/C968Project/Views/AddModifyProductScreen.Designer.cs b/C968Project/Views/AddModifyProductScreen.Designer.cs index 6379c07..912941f 100644 --- a/C968Project/Views/AddModifyProductScreen.Designer.cs +++ b/C968Project/Views/AddModifyProductScreen.Designer.cs @@ -178,6 +178,7 @@ searchButton.TabIndex = 19; searchButton.Text = "Search"; searchButton.UseVisualStyleBackColor = true; + searchButton.Click += searchButton_Click; // // searchTextBox // @@ -188,9 +189,12 @@ // // allPartsDataGridView // + allPartsDataGridView.AllowUserToAddRows = false; + allPartsDataGridView.AllowUserToDeleteRows = false; allPartsDataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; allPartsDataGridView.Location = new Point(407, 91); allPartsDataGridView.Name = "allPartsDataGridView"; + allPartsDataGridView.ReadOnly = true; allPartsDataGridView.Size = new Size(482, 150); allPartsDataGridView.TabIndex = 21; // @@ -214,9 +218,11 @@ // // associatedPartsDataGridView // + associatedPartsDataGridView.AllowUserToAddRows = false; associatedPartsDataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; associatedPartsDataGridView.Location = new Point(407, 361); associatedPartsDataGridView.Name = "associatedPartsDataGridView"; + associatedPartsDataGridView.ReadOnly = true; associatedPartsDataGridView.Size = new Size(482, 150); associatedPartsDataGridView.TabIndex = 25; // diff --git a/C968Project/Views/AddModifyProductScreen.cs b/C968Project/Views/AddModifyProductScreen.cs index e06a0d2..159ea44 100644 --- a/C968Project/Views/AddModifyProductScreen.cs +++ b/C968Project/Views/AddModifyProductScreen.cs @@ -45,7 +45,7 @@ namespace C968Project.Views allPartsDataGridView.DataSource = Program.Inventory.Parts; - ValidateInputs(); + ValidateInputs(true); } private void PopulateProductData(Product product) @@ -117,7 +117,7 @@ namespace C968Project.Views private void saveButton_Click(object sender, EventArgs e) { - if (ValidateInputs()) + if (ValidateInputs()) { if (_screenOption is ScreenOption.ADD) { @@ -185,11 +185,14 @@ namespace C968Project.Views ValidateName(); } - private void ValidateName() + private string ValidateName() { + string err = string.Empty; + if (nameTextBox.Text == string.Empty) { - errorProvider1.SetError(nameTextBox, "Please enter a product name"); + err = "Must have a product name\n"; + errorProvider1.SetError(nameTextBox, "Must have a product name"); _isNameValid = false; } else @@ -199,6 +202,7 @@ namespace C968Project.Views } Helpers.SetTextBoxValidationState(nameTextBox, _isNameValid); + return err; } private void inventoryTextBox_TextChanged(object sender, EventArgs e) @@ -206,8 +210,9 @@ namespace C968Project.Views ValidateInventory(); } - private void ValidateInventory() + private string ValidateInventory() { + string err = string.Empty; int inventory = 0; if (inventoryTextBox.Text != string.Empty && int.TryParse(inventoryTextBox.Text, out inventory)) @@ -216,11 +221,13 @@ namespace C968Project.Views { if (inventory > _validatedMax) { + err = $"Inventory must be less than Max: {_validatedMax}\n"; errorProvider1.SetError(inventoryTextBox, $"Must be less than Max: {_validatedMax}"); _isInventoryValid = false; } else if (inventory < _validatedMin) { + err = $"Inventory must be greater than Min: {_validatedMin}\n"; errorProvider1.SetError(inventoryTextBox, $"Must be greater than Min: {_validatedMin}"); _isInventoryValid = false; } @@ -232,17 +239,20 @@ namespace C968Project.Views } else { + err = $"Inventory can't be set without valid Min and Max values\n"; errorProvider1.SetError(inventoryTextBox, $"Min and Max values must be set"); _isInventoryValid = false; } } else { + err = $"Inventory must contain an integer\n"; _isInventoryValid = false; errorProvider1.SetError(inventoryTextBox, "Field must contain an integer value"); } Helpers.SetTextBoxValidationState(inventoryTextBox, _isInventoryValid); + return err; } private void priceTextBox_TextChanged(object sender, EventArgs e) @@ -250,8 +260,9 @@ namespace C968Project.Views ValidatePrice(); } - private void ValidatePrice() + private string ValidatePrice() { + string err = string.Empty; float price = 0f; if (priceTextBox.Text != string.Empty && float.TryParse(priceTextBox.Text, out price)) @@ -262,10 +273,12 @@ namespace C968Project.Views else { _isPriceValid = false; - errorProvider1.SetError(priceTextBox, "Field must contain a floating point number"); + err = "Price must contain a decimal value\n"; + errorProvider1.SetError(priceTextBox, "Field must contain a decimal value"); } Helpers.SetTextBoxValidationState(priceTextBox, _isPriceValid); + return err; } private void maxTextBox_TextChanged(object sender, EventArgs e) @@ -273,8 +286,9 @@ namespace C968Project.Views ValidateMax(); } - private void ValidateMax() + private string ValidateMax() { + string err = string.Empty; int max = 0; if (maxTextBox.Text != string.Empty && int.TryParse(maxTextBox.Text, out max)) { @@ -286,10 +300,19 @@ namespace C968Project.Views { _isMaxValid = false; errorProvider1.SetError(maxTextBox, "Field must contain an integer value"); + err = "Max must be an integer value\n"; + } + + if (_isMinValid && _isMaxValid && _validatedMax < _validatedMin) + { + _isMaxValid = false; + err = $"Max cannot be less than Min: {_validatedMin}\n"; + errorProvider1.SetError(maxTextBox, $"Max cannot be less than Min: {_validatedMin}"); } ValidateInventory(); Helpers.SetTextBoxValidationState(maxTextBox, _isMaxValid); + return err; } private void minTextBox_TextChanged(object sender, EventArgs e) @@ -297,8 +320,9 @@ namespace C968Project.Views ValidateMin(); } - private void ValidateMin() + private string ValidateMin() { + string err = string.Empty; int min = 0; if (minTextBox.Text != string.Empty && int.TryParse(minTextBox.Text, out min)) { @@ -310,21 +334,45 @@ namespace C968Project.Views { _isMinValid = false; errorProvider1.SetError(minTextBox, "Field must contain an integer value"); + err = "Min must be an integer value\n"; + } + + if (_isMinValid && _isMaxValid && _validatedMin > _validatedMax) + { + _isMinValid = false; + err = $"Min cannot be more than Max: {_validatedMax}\n"; + errorProvider1.SetError(maxTextBox, $"Min cannot be more than Max: {_validatedMax}"); } ValidateInventory(); Helpers.SetTextBoxValidationState(minTextBox, _isMinValid); + return err; } - private bool ValidateInputs() + private bool ValidateInputs(bool initial = false) { - ValidateName(); - ValidateInventory(); - ValidatePrice(); - ValidateMin(); - ValidateMax(); + bool valid = false; + string err = string.Empty; - return _isNameValid && _isInventoryValid && _isPriceValid && _isMinValid && _isMaxValid; + err += ValidateName(); + err += ValidateInventory(); + err += ValidatePrice(); + err += ValidateMin(); + err += ValidateMax(); + + valid = _isNameValid && _isInventoryValid && _isPriceValid && _isMinValid && _isMaxValid; + + if (!valid && !initial) + { + Helpers.ShowErrorMessage(err, "Validation error"); + } + + return valid; + } + + private void searchButton_Click(object sender, EventArgs e) + { + Helpers.SearchDataGridView(allPartsDataGridView, searchTextBox.Text); } } } diff --git a/C968Project/Views/AddModifyProductScreen.resx b/C968Project/Views/AddModifyProductScreen.resx index 6bcea65..4f5109e 100644 --- a/C968Project/Views/AddModifyProductScreen.resx +++ b/C968Project/Views/AddModifyProductScreen.resx @@ -123,4 +123,7 @@ True + + 60 + \ No newline at end of file diff --git a/C968Project/Views/MainScreen.Designer.cs b/C968Project/Views/MainScreen.Designer.cs index 7d0aea4..6c9e2d7 100644 --- a/C968Project/Views/MainScreen.Designer.cs +++ b/C968Project/Views/MainScreen.Designer.cs @@ -156,10 +156,12 @@ partial class MainScreen // // productsDataGridView // + productsDataGridView.AllowUserToAddRows = false; productsDataGridView.Anchor = AnchorStyles.Right; productsDataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; productsDataGridView.Location = new Point(477, 112); productsDataGridView.Name = "productsDataGridView"; + productsDataGridView.ReadOnly = true; productsDataGridView.Size = new Size(440, 162); productsDataGridView.TabIndex = 9; // @@ -237,10 +239,12 @@ partial class MainScreen // // partsDataGridView // + partsDataGridView.AllowUserToAddRows = false; partsDataGridView.Anchor = AnchorStyles.Left; partsDataGridView.ColumnHeadersHeightSizeMode = DataGridViewColumnHeadersHeightSizeMode.AutoSize; partsDataGridView.Location = new Point(12, 112); partsDataGridView.Name = "partsDataGridView"; + partsDataGridView.ReadOnly = true; partsDataGridView.Size = new Size(440, 162); partsDataGridView.TabIndex = 0; // diff --git a/C968Project/Views/MainScreen.cs b/C968Project/Views/MainScreen.cs index 6726587..e948fda 100644 --- a/C968Project/Views/MainScreen.cs +++ b/C968Project/Views/MainScreen.cs @@ -68,7 +68,7 @@ public partial class MainScreen : Form private void partsSearchButton_Click(object sender, EventArgs e) { - // TODO: Search functionality + Helpers.SearchDataGridView(partsDataGridView, partsSearchTextBox.Text); } // --- Products @@ -126,7 +126,7 @@ public partial class MainScreen : Form private void productsSearchButton_Click(object sender, EventArgs e) { - // TODO: Search functionality + Helpers.SearchDataGridView(productsDataGridView, productsSearchTextBox.Text); } diff --git a/GUI Mock up.docx b/GUI Mock up.docx deleted file mode 100644 index 29f19f7..0000000 Binary files a/GUI Mock up.docx and /dev/null differ diff --git a/UML Class Diagram.pdf b/UML Class Diagram.pdf deleted file mode 100644 index 92a2f23..0000000 Binary files a/UML Class Diagram.pdf and /dev/null differ