using System; using System.Collections.Generic; using System.Data; using System.Drawing; using System.Linq; using System.Runtime.InteropServices; using System.Text.RegularExpressions; using System.Windows.Forms; namespace AdvertsingProfitControl { public partial class frmMain : Form { private double _gActualTotaSalesCalculatedTotal = 0; private double _gActualTotalProfitReturnCalculatedTotal = 0; private double _gCostOfSalesCalculatedTotal = 0; private List _gDateStringCollection = new List(); readonly LogConsole _console = LogConsole.GetStaticInstance; public frmMain() { InitializeComponent(); //Set the maximum and minimum sizes for the form. MaximumSize = new Size(1200, 650); MinimumSize = new Size(1000, 550); } private void frmMain_Load(object sender, EventArgs e) { FillDateSuggestionComboBoxes(); BuildAndFillDataGridTables(); CalculateProfitAnalysis(); CalculateGrossProfit(); _console.Show(); } private void UpdateDataGridViewInformation(object sender, EventArgs e) { string dateString = monthComboBox.Text + "/" + dayComboBox.Text + "/" + yearComboBox.Text; BuildAndFillDataGridTables(dateString); CalculateProfitAnalysis(); CalculateGrossProfit(); } /// /// Builds and fills the DataGridView tables on the main form /// from the either the most recent date or the date specified in the parameter. /// /// The date of records to display to the user, if no date is specified then the most recent date is used. private void BuildAndFillDataGridTables(string dateString = "") { //Deprecated var dataBaseReader = new RetrieveFromDatabase(); // var dateId = ""; //Check to see if a parameter has been passed. if (dateString == "") { //IF non were, then grab the most recent date ID from the database and use that. dateId = dataBaseReader.RetrieveMostRecentDateId(); _console.WriteToLog(LogConsole.Level.Info, dateId != "-1" ? "Most recent date ID is " + dateId : "Most recent date ID is unavailable."); } else { //ELSE IF one was passed, then use it's ID to build the tables. dateId = dataBaseReader.RetrieveDateIdByDateString(dateString); _console.WriteToLog(LogConsole.Level.Info, dateId != "-1" ? "Date ID for " + dateString + " is resolved to have the ID of " + dateId + "." : "The date " + dateString + " could not be found in the database."); if (dateId == "-1") { _gDateStringCollection.Remove(dateString); } } //Now check to make sure there were no errors grabbing the ID, IF there were return. if (dateId == "-1") return; //Clear the class global variables to prevents calculation mishaps. _gActualTotaSalesCalculatedTotal = 0; _gActualTotalProfitReturnCalculatedTotal = 0; _gCostOfSalesCalculatedTotal = 0; //Clear all DataGridViews since the date supplied is valid and in the database. projectedSalesMainDataGrid.DataSource = null; inventoryDataGridView.DataSource = null; actualSalesMainDataGidView.DataSource = null; suppliersDataGridView.DataSource = null; weeklySalesDataGridView.DataSource = null; var indexOfAdSpecialRow = -1; var regexGroupCategoryparser = new Regex(@"^(\d)?\|\d"); //Begin by grabbing the Projections table var tempTable = dataBaseReader.ReturnProjectionsTable(dateId); if (tempTable.Rows.Count > 0) { projectedSalesMainDataGrid.DataSource = SumSalesTable(tempTable); string adCategory = ""; for (var i = 0; i < projectedSalesMainDataGrid.Rows.Count; i++) { int castedValue = 0; if ((string)projectedSalesMainDataGrid.Rows[i].Cells[7].EditedFormattedValue == "1") { projectedSalesMainDataGrid.Rows[i].DefaultCellStyle.BackColor = Color.LightGray; }else if ((string) projectedSalesMainDataGrid.Rows[i].Cells[7].EditedFormattedValue == "2") { projectedSalesMainDataGrid.Rows[i].DefaultCellStyle.BackColor = Color.LightBlue; } else if ( regexGroupCategoryparser.IsMatch( (string) projectedSalesMainDataGrid.Rows[i].Cells[7].EditedFormattedValue)) { string[] spam = new string[2]; spam = ParseAdSpecialRows(projectedSalesMainDataGrid.Rows[i].Cells[7].EditedFormattedValue.ToString()); if (spam.Length > 1) { adCategory = spam[1]; } else { adCategory = spam[0]; } if (indexOfAdSpecialRow == -1) { indexOfAdSpecialRow = i; } if (spam[0] == "1") { projectedSalesMainDataGrid.Rows[i].DefaultCellStyle.BackColor = Color.LightGray; }else if (spam[0] == "2") { projectedSalesMainDataGrid.Rows[i].DefaultCellStyle.BackColor = Color.LightBlue; } } } var dataGridViewColumn = projectedSalesMainDataGrid.Columns["FK_GroupID"]; if (dataGridViewColumn != null) dataGridViewColumn.Visible = false; } //Grabbing the Inventory table tempTable = dataBaseReader.ReturnInventoryTable(dateId); if (tempTable.Rows.Count > 0) { inventoryDataGridView.DataSource = tempTable; string adCategory = ""; for (var i = 0; i < inventoryDataGridView.Rows.Count; i++) { int castedValue = 0; if ((string)inventoryDataGridView.Rows[i].Cells[5].EditedFormattedValue == "1") { inventoryDataGridView.Rows[i].DefaultCellStyle.BackColor = Color.LightGray; } else if ((string)inventoryDataGridView.Rows[i].Cells[5].EditedFormattedValue == "2") { inventoryDataGridView.Rows[i].DefaultCellStyle.BackColor = Color.LightBlue; } else if ( regexGroupCategoryparser.IsMatch( (string)inventoryDataGridView.Rows[i].Cells[5].EditedFormattedValue)) { string[] spam = new string[2]; spam = ParseAdSpecialRows(inventoryDataGridView.Rows[i].Cells[5].EditedFormattedValue.ToString()); if (spam.Length > 1) { adCategory = spam[1]; } else { adCategory = spam[0]; } if (spam[0] == "1") { inventoryDataGridView.Rows[i].DefaultCellStyle.BackColor = Color.LightGray; } else if (spam[0] == "2") { inventoryDataGridView.Rows[i].DefaultCellStyle.BackColor = Color.LightBlue; } } } var dataGridViewColumn = inventoryDataGridView.Columns["FK_GroupID"]; if (dataGridViewColumn != null) dataGridViewColumn.Visible = false; } //And the Actual Sales table tempTable = dataBaseReader.ReturnActualSales(dateId); if (tempTable.Rows.Count > 0) { actualSalesMainDataGidView.DataSource = SumSalesTable(tempTable); string adCategory = ""; for (var i = 0; i < actualSalesMainDataGidView.Rows.Count; i++) { int castedValue = 0; if ((string)actualSalesMainDataGidView.Rows[i].Cells[7].EditedFormattedValue == "1") { actualSalesMainDataGidView.Rows[i].DefaultCellStyle.BackColor = Color.LightGray; } else if ((string)actualSalesMainDataGidView.Rows[i].Cells[7].EditedFormattedValue == "2") { actualSalesMainDataGidView.Rows[i].DefaultCellStyle.BackColor = Color.LightBlue; } else if ( regexGroupCategoryparser.IsMatch( (string)actualSalesMainDataGidView.Rows[i].Cells[7].EditedFormattedValue)) { string[] spam = new string[2]; spam = ParseAdSpecialRows(actualSalesMainDataGidView.Rows[i].Cells[7].EditedFormattedValue.ToString()); if (spam.Length > 1) { adCategory = spam[1]; } else { adCategory = spam[0]; } if (spam[0] == "1") { actualSalesMainDataGidView.Rows[i].DefaultCellStyle.BackColor = Color.LightGray; } else if (spam[0] == "2") { actualSalesMainDataGidView.Rows[i].DefaultCellStyle.BackColor = Color.LightBlue; } } } var year = actualSalesMainDataGidView.Columns["FK_GroupID"]; if (year != null) year.Visible = false; } //Next the Invoices table tempTable = dataBaseReader.ReturnInvoiceTable(dateId); if (tempTable.Rows.Count > 0) { suppliersDataGridView.DataSource = SumCostOfSales(tempTable); } //And finally the weekly sales tempTable = dataBaseReader.ReturnWeeklySalesFromDateID(dateId); if (tempTable.Rows.Count > 0) { weeklySalesDataGridView.DataSource = tempTable; } commentsTextBox.Text = dataBaseReader.RetrieveComments(dateId); } private void CalculateProfitAnalysis(double shrink = 0.30) { if (Math.Abs(_gActualTotaSalesCalculatedTotal) < 1 || Math.Abs(_gActualTotalProfitReturnCalculatedTotal) < 1) { //Clear the labels... if (weeklySalesDataGridView.Rows.Count == 0 || weeklySalesDataGridView.Rows[0].Cells[7].EditedFormattedValue.ToString() == "0.0000") { departmentSalesLabel.Text = "Department Sales: No Weekly Sales Found."; departmentSalesLabel.ForeColor = Color.Red; } if (_gActualTotaSalesCalculatedTotal == 0) { salesProducedLabel.Text = "Sales Produced By Ad Items (A): No Values to Total."; salesProducedLabel.ForeColor = Color.Red; } remainingSalesLabel.Text = "Remaining Sales: "; if (_gActualTotalProfitReturnCalculatedTotal == 0) { totalProfitFromAdItemsLabel.Text = "Total Profit Return From Ad Items (B): No Values to Total."; totalProfitFromAdItemsLabel.ForeColor = Color.Red; } totalProfitReturnFromRemaingLabel.Text = "Total Profit Return From Remaining Sales: "; totalProfitReturnLabel.Text = "Total Profit Return: "; return; } double departmentSales = 0; Double.TryParse(weeklySalesDataGridView.Rows[0].Cells[7].EditedFormattedValue.ToString(), out departmentSales); //Since there are department sales, change the label's color to make sure it doesn't appear as an error. departmentSalesLabel.ForeColor = Color.Black; departmentSalesLabel.Text = "Department Sales: " + departmentSales.ToString("C"); //Assume that the sales produced is larger then zero (0). salesProducedLabel.ForeColor = Color.Black; salesProducedLabel.Text = "Sales Produced By Ad Items (A): " + _gActualTotaSalesCalculatedTotal.ToString("C"); double remainingSales = departmentSales - _gActualTotaSalesCalculatedTotal; remainingSalesLabel.Text = "Remaining Sales: " + remainingSales.ToString("C"); //Again assume the total profit return is larger then zero (0). totalProfitFromAdItemsLabel.ForeColor = Color.Black; totalProfitFromAdItemsLabel.Text = "Total Profit Return From Ad Items (B): " + _gActualTotalProfitReturnCalculatedTotal.ToString("C"); //Shrink is being used as a place holder for Cross Profit % which is obtained by dividing gActualTotalProfitReturnCalculatedTotal by the department weekly retail sales. double totalProfitReturnFromRemainingSales = shrink * remainingSales; // totalProfitReturnFromRemaingLabel.Text = "Total Profit Return From Remaining Sales: " + totalProfitReturnFromRemainingSales.ToString("C"); double totalProfitReturn = _gActualTotalProfitReturnCalculatedTotal + totalProfitReturnFromRemainingSales; totalProfitReturnLabel.Text = "Total Profit Return: " + totalProfitReturn.ToString("C"); } private void CalculateCostOfSales() { //? } private void CalculateGrossProfit() { if (Math.Abs(_gCostOfSalesCalculatedTotal) < 1) { //IF Cost of Sales hasn't been calculated, then clear labels and return. if (weeklySalesDataGridView.Rows.Count == 0 || weeklySalesDataGridView.Rows[0].Cells[7].EditedFormattedValue.ToString() == "0.0000") { grossProfitTotalSales.Text = "Total Sales: No Weekly Sales Found."; grossProfitTotalSales.ForeColor = Color.Red; } grossProfitLessCostOfSales.Text = "Less Cost of Sales: "; grossProfitDollarGrossProfitLabel.Text = "Dollar Gross Profit: "; perfectGrossProfitLabel.Text = "Percent Gross Profit: "; return; } double totalSales = Convert.ToDouble(weeklySalesDataGridView.Rows[0].Cells[7].EditedFormattedValue.ToString()); grossProfitTotalSales.ForeColor = Color.Black; grossProfitTotalSales.Text = "Total Sales: " + totalSales.ToString("C"); grossProfitLessCostOfSales.Text = "Less Cost of Sales: " + _gCostOfSalesCalculatedTotal.ToString("C"); double dollarGrossProfit = totalSales - _gCostOfSalesCalculatedTotal; grossProfitDollarGrossProfitLabel.Text = "Dollar Gross Profit: " + dollarGrossProfit.ToString("C"); double grossProfitPercent = dollarGrossProfit / totalSales; perfectGrossProfitLabel.Text = "Percent Gross Profit: " + grossProfitPercent.ToString("P"); } private void addRecordToolStripMenuItem_Click(object sender, EventArgs e) { frmAddRecord recordForm = new frmAddRecord(); recordForm.ShowDialog(); FillDateSuggestionComboBoxes(); BuildAndFillDataGridTables(); CalculateProfitAnalysis(); CalculateGrossProfit(); } /// /// Appends a new "Totals" row to the end of the DataTable that is passed in /// and sums up the Total Sales and Total Profit Return columns as well as /// storing the Total Sales and Total Profit Return in their respective /// class wide variables for use with other functions. /// /// The sales table to be summed up. /// private DataTable SumSalesTable(DataTable table) { //IF the table is null OR has an invalid column count then return. if (table == null || table.Columns.Count < 7) return table; //Both Projections and Actual tables have the Total Sales and Total Profit Return columns in the same position, //indexes three (3) and six (6) respectively. double totalSalesSum = 0; double totalProfitReturnSum = 0; for (var i = 0; i < table.Rows.Count; i++) { totalSalesSum += Convert.ToDouble(table.Rows[i][3]); totalProfitReturnSum += Convert.ToDouble(table.Rows[i][6]); } //Once the totals have been calculated store them in the class wide variables so other methods can use them. _gActualTotaSalesCalculatedTotal = totalSalesSum; _gActualTotalProfitReturnCalculatedTotal = totalProfitReturnSum; //Create an object array to store the summed values and add them at the end to the table before returning it. object[] rowContents = new object[table.Columns.Count]; rowContents[0] = "Total"; rowContents[3] = totalSalesSum; rowContents[6] = totalProfitReturnSum; table.Rows.Add(rowContents); return table; } /// /// Appends a new "Totals" row to the end of the Invoice table that is passed in /// and sums up the Net Cost of Invoices column as well as storing the total Costs of Sales /// into the class wide variable for use with other functions. /// /// The Invoice table to summed. /// private DataTable SumCostOfSales(DataTable invoiceTable) { //Check for a null parameter OR if the column count is less then six (6) as any less means the database isn't returning correctly. if(invoiceTable == null || invoiceTable.Columns.Count < 6) return invoiceTable; double costOfSalesSum = 0; for (var i = 0; i < invoiceTable.Rows.Count; i++) { costOfSalesSum += Convert.ToDouble(invoiceTable.Rows[i][4]); } _gCostOfSalesCalculatedTotal = costOfSalesSum; object[] invoiceTotalRow = new object[invoiceTable.Columns.Count]; invoiceTotalRow[0] = "Total Purchases"; invoiceTotalRow[4] = costOfSalesSum; invoiceTable.Rows.Add(invoiceTotalRow); return invoiceTable; } private void showHideConsoleHelpMainMenu_Click(object sender, EventArgs e) { if (_console.IsVisable) { _console.Hide(); } else { _console.Show(); } } /// /// Grabs all dates from the database and splits the returned strings /// into months, days, and years and stores them in their respective /// combo boxes to display to the user. Also stores the list of dates /// inside a class wide variable. /// private void FillDateSuggestionComboBoxes() { //Create a connection to the database retrieval class. var dbReader = new RetrieveFromDatabase(); //Grab the most recent date in the database. var mostRecentDateTime = dbReader.ReturnMostRecentDateString(); var mostRecentDateString = mostRecentDateTime.ToString("MM/dd/yyyy"); //Check to see if the return value is null and IF so log the error and return. if(mostRecentDateString == ""){ _console.WriteToLog(LogConsole.Level.Error, "No dates could be found in the database."); return;} //Otherwise, if there was a return date, split it into a array. var mostRecentDateParts = mostRecentDateString.Split('/'); //Grab only the most recent years in the database (only say 2015) and fill a table with the dates. Indexes are as follows: [0] is Month, [1] is Day and [2] is Year. DataTable oneYearDatesTable = dbReader.ReturnDateStringsLike(mostRecentDateParts[0] + "/" + mostRecentDateParts[1] + "/" + mostRecentDateParts[2]); //Suspend the control's drawing so the user doesn't see any ugly enumeration and index changing. DrawingControl.SuspendDrawing(dateSelectorPanel); //Considering there was a return value for the most recent date, its safe to assume there is at least one date in the database, so clear the class's date collection. _gDateStringCollection.Clear(); monthComboBox.Items.Clear(); dayComboBox.Items.Clear(); yearComboBox.Items.Clear(); monthComboBox.SelectedIndexChanged -= UpdateDaysOfMonth; dayComboBox.SelectedIndexChanged -= UpdateDataGridViewInformation; yearComboBox.SelectedIndexChanged -= UpdateDaysOfMonthByYear; //Now spin through the oneYearDatesTable and fill the class wide object with all the dates for the most recent year. for (var i = 0; i < oneYearDatesTable.Rows.Count; i ++) { var fullDateTime = (DateTime) oneYearDatesTable.Rows[i][0]; var fullDateString = fullDateTime.ToString("MM/dd/yyyy"); //Check for nulls just to be paranoid. if (fullDateString == "") { return; } //IF the date string collection already contains the date, then continue to the next iteration. if (_gDateStringCollection.Contains(fullDateString)) { continue; } _gDateStringCollection.Add(fullDateString); } var dayBasedOnMonthAndYeaRegex = new Regex("^0?" + mostRecentDateParts[0] + @"/\d{2}/" + mostRecentDateParts[2]); var monthBasedOnYearRegex = new Regex(@"^\d{2}/\d{2}/" + mostRecentDateParts[2]); for (var i = 0; i < _gDateStringCollection.Count; i++) { string[] dateArray = _gDateStringCollection[i].Split('/'); var month = dateArray[0]; var day =dateArray[1]; if (dayBasedOnMonthAndYeaRegex.IsMatch(_gDateStringCollection[i])) { dayComboBox.Items.Add(day); } if (monthBasedOnYearRegex.IsMatch(_gDateStringCollection[i])) { if (!monthComboBox.Items.Contains(month)) { monthComboBox.Items.Add(month); } } } var yearsInDatabase = dbReader.ReturnUniqueYearsList(); foreach (var year in yearsInDatabase) { yearComboBox.Items.Add(year); } if (dayComboBox.Items.Count >= 1 && yearComboBox.Items.Count >= 1 && monthComboBox.Items.Count >= 1) { monthComboBox.SelectedIndex = monthComboBox.Items.Count - 1; dayComboBox.SelectedIndex = dayComboBox.Items.Count - 1; yearComboBox.SelectedIndex = yearComboBox.Items.Count - 1; monthComboBox.Enabled = true; dayComboBox.Enabled = true; yearComboBox.Enabled = true; } else { monthComboBox.Enabled = false; dayComboBox.Enabled = false; yearComboBox.Enabled = false; } monthComboBox.SelectedIndexChanged += UpdateDaysOfMonth; dayComboBox.SelectedIndexChanged += UpdateDataGridViewInformation; yearComboBox.SelectedIndexChanged += UpdateDaysOfMonthByYear; DrawingControl.ResumeDrawing(dateSelectorPanel); } private void UpdateDaysOfMonth(object sender, EventArgs e) { if (yearComboBox.SelectedIndex == -1) return; var year = yearComboBox.SelectedItem.ToString(); var month = monthComboBox.SelectedItem.ToString(); var dateParserPattern = new Regex("^" + month + @"\/\d{2}\/" + year); dayComboBox.Items.Clear(); for (var i = 0; i < _gDateStringCollection.Count; i++) { if (dateParserPattern.IsMatch(_gDateStringCollection[i])) { var dateArray = _gDateStringCollection[i].Split('/'); var day = dateArray[1]; dayComboBox.Items.Add(day); } } if (dayComboBox.Items.Count > 0) { dayComboBox.SelectedIndex = dayComboBox.Items.Count - 1; } CalculateProfitAnalysis(); CalculateGrossProfit(); } /// /// Fires when the Year combo box's index changes. /// /// /// private void UpdateDaysOfMonthByYear(object sender, EventArgs e) { //Obligatory database retrieval call... var dbReader = new RetrieveFromDatabase(); //First, grab the year and the month from their respective combo boxes. var year = yearComboBox.SelectedItem.ToString(); var month = monthComboBox.SelectedItem.ToString(); //Since we can more or less be certain that nothing is null, clear the current date collection. _gDateStringCollection.Clear(); var months = dbReader.ReturnUniqueMonthsList(month + "/" + dayComboBox.SelectedItem + "/" + year); var mostRecentMonth = months.Max(); if (mostRecentMonth.Length == 1) { mostRecentMonth = "0" + mostRecentMonth; } var selectedYearDates = dbReader.ReturnDateStringsLike(month + "/" + dayComboBox.SelectedItem + "/" + year); for (var i = 0; i < selectedYearDates.Rows.Count; i++) { var trimmedDateString = (DateTime) selectedYearDates.Rows[i][0]; _gDateStringCollection.Add(trimmedDateString.ToString("MM/dd/yyyy")); } //Clear the month and day combo boxes and unregister their event handlers. dayComboBox.Items.Clear(); monthComboBox.Items.Clear(); monthComboBox.SelectedIndexChanged -= UpdateDaysOfMonth; dayComboBox.SelectedIndexChanged -= UpdateDataGridViewInformation; for (var i = 0; i < _gDateStringCollection.Count; i ++) { var dateArray = _gDateStringCollection[i].Split('/'); month = dateArray[0]; //Declare the patterns to look for when enumerating the combo boxes. var dayBasedOnMonthAndYeaRegex = new Regex(@"^(" + mostRecentMonth + @"\/\d{2}\/" + year + ")"); //Only allows days that are actually part of the month and year. var day = dateArray[1]; if (dayBasedOnMonthAndYeaRegex.IsMatch(_gDateStringCollection[i])) { dayComboBox.Items.Add(day); } if (!monthComboBox.Items.Contains(month)) { monthComboBox.Items.Add(month); } } if (dayComboBox.Items.Count > 0) { dayComboBox.SelectedIndex = dayComboBox.Items.Count - 1; } if (monthComboBox.Items.Count > 0) { monthComboBox.SelectedIndex = monthComboBox.Items.Count - 1; } //Now re-register the event handlers monthComboBox.SelectedIndexChanged += UpdateDaysOfMonth; dayComboBox.SelectedIndexChanged += UpdateDataGridViewInformation; BuildAndFillDataGridTables(monthComboBox.SelectedItem + "/" + dayComboBox.SelectedItem + "/" + year); CalculateProfitAnalysis(); CalculateGrossProfit(); } private string[] ParseAdSpecialRows(string groupIdentifier) { var groupCategory = new string[2]; var dbReader = new RetrieveFromDatabase(); var patternForOnlyPipeAndAdSpecial = new Regex(@"^\|\d{1}"); var patternForBothNumbersOnPipe = new Regex(@"^\d{1}\|\d{1}"); if (patternForOnlyPipeAndAdSpecial.IsMatch(groupIdentifier)) { groupCategory[0] = groupIdentifier; if (groupIdentifier[0].ToString() != "") { groupCategory[0] = groupCategory[0].Replace("|", ""); groupCategory[0] = dbReader.ReturnGroupNameFromGroupId(groupCategory[0]); } }else if (patternForBothNumbersOnPipe.IsMatch(groupIdentifier)) { string[] temp = groupIdentifier.Split('|'); groupCategory[0] = temp[0]; groupCategory[1] = temp[1]; groupCategory[1] = dbReader.ReturnGroupNameFromGroupId(groupCategory[1]); } return groupCategory; } private void adSpecialKeyWordsToolsMainMenu_Click(object sender, EventArgs e) { var keyWordRegister = new frmAdSpecialRegister(); keyWordRegister.ShowDialog(); } private void deleteRecordsMainMenu_Click(object sender, EventArgs e) { var frmDeleteRecord = new frmDeleteRecord(); frmDeleteRecord.ShowDialog(); FillDateSuggestionComboBoxes(); BuildAndFillDataGridTables(); CalculateProfitAnalysis(); CalculateGrossProfit(); } } //http://stackoverflow.com/questions/487661/how-do-i-suspend-painting-for-a-control-and-its-children class DrawingControl { [DllImport("user32.dll")] public static extern int SendMessage(IntPtr hWnd, Int32 wMsg, bool wParam, Int32 lParam); private const int WM_SETREDRAW = 11; public static void SuspendDrawing(Control parent) { SendMessage(parent.Handle, WM_SETREDRAW, false, 0); } public static void ResumeDrawing(Control parent) { SendMessage(parent.Handle, WM_SETREDRAW, true, 0); parent.Refresh(); } } }