diff --git a/GradeCalc/DataGridViewNumericUpDownCell.cs b/GradeCalc/DataGridViewNumericUpDownCell.cs deleted file mode 100644 index 0f1245c..0000000 --- a/GradeCalc/DataGridViewNumericUpDownCell.cs +++ /dev/null @@ -1,673 +0,0 @@ -using System; -using System.ComponentModel; -using System.Diagnostics; -using System.Drawing; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Windows.Forms; - -namespace GradeCalc -{ - public class DataGridViewNumericUpDownCell : DataGridViewTextBoxCell - { - // Default dimensions of the static rendering bitmap used for the painting of the non-edited cells - private const int DATAGRIDVIEWNUMERICUPDOWNCELL_defaultRenderingBitmapWidth = 100; - - private const int DATAGRIDVIEWNUMERICUPDOWNCELL_defaultRenderingBitmapHeight = 22; - - // Default value of the DecimalPlaces property - internal const int DATAGRIDVIEWNUMERICUPDOWNCELL_defaultDecimalPlaces = 0; - - // Default value of the Increment property - internal const decimal DATAGRIDVIEWNUMERICUPDOWNCELL_defaultIncrement = decimal.One; - - // Default value of the Maximum property - internal const decimal DATAGRIDVIEWNUMERICUPDOWNCELL_defaultMaximum = (decimal) 100.0; - - // Default value of the Minimum property - internal const decimal DATAGRIDVIEWNUMERICUPDOWNCELL_defaultMinimum = decimal.Zero; - - // Default value of the ThousandsSeparator property - internal const bool DATAGRIDVIEWNUMERICUPDOWNCELL_defaultThousandsSeparator = false; - - // Used in TranslateAlignment function - private static readonly DataGridViewContentAlignment anyRight = DataGridViewContentAlignment.TopRight | - DataGridViewContentAlignment.MiddleRight | - DataGridViewContentAlignment.BottomRight; - - private static readonly DataGridViewContentAlignment anyCenter = DataGridViewContentAlignment.TopCenter | - DataGridViewContentAlignment.MiddleCenter | - DataGridViewContentAlignment.BottomCenter; - - // Type of this cell's editing control - private static readonly Type defaultEditType = typeof(DataGridViewNumericUpDownEditingControl); - - // Type of this cell's value. The formatted value type is string, the same as the base class DataGridViewTextBoxCell - private static readonly Type defaultValueType = typeof(decimal); - - // The bitmap used to paint the non-edited cells via a call to NumericUpDown.DrawToBitmap - [ThreadStatic] private static Bitmap renderingBitmap; - - // The NumericUpDown control used to paint the non-edited cells via a call to NumericUpDown.DrawToBitmap - [ThreadStatic] private static NumericUpDown paintingNumericUpDown; - - private int decimalPlaces; // Caches the value of the DecimalPlaces property - private decimal increment; // Caches the value of the Increment property - private decimal maximum; // Caches the value of the Maximum property - private decimal minimum; // Caches the value of the Minimum property - private bool thousandsSeparator; // Caches the value of the ThousandsSeparator property - - /// - /// Constructor for the DataGridViewNumericUpDownCell cell type - /// - public DataGridViewNumericUpDownCell() - { - // Create a thread specific bitmap used for the painting of the non-edited cells - if (renderingBitmap == null) - renderingBitmap = new Bitmap(DATAGRIDVIEWNUMERICUPDOWNCELL_defaultRenderingBitmapWidth, - DATAGRIDVIEWNUMERICUPDOWNCELL_defaultRenderingBitmapHeight); - - // Create a thread specific NumericUpDown control used for the painting of the non-edited cells - if (paintingNumericUpDown == null) - { - paintingNumericUpDown = new NumericUpDown(); - // Some properties only need to be set once for the lifetime of the control: - paintingNumericUpDown.BorderStyle = BorderStyle.None; - paintingNumericUpDown.Maximum = decimal.MaxValue / 10; - paintingNumericUpDown.Minimum = decimal.MinValue / 10; - } - - // Set the default values of the properties: - decimalPlaces = DATAGRIDVIEWNUMERICUPDOWNCELL_defaultDecimalPlaces; - increment = DATAGRIDVIEWNUMERICUPDOWNCELL_defaultIncrement; - minimum = DATAGRIDVIEWNUMERICUPDOWNCELL_defaultMinimum; - maximum = DATAGRIDVIEWNUMERICUPDOWNCELL_defaultMaximum; - thousandsSeparator = DATAGRIDVIEWNUMERICUPDOWNCELL_defaultThousandsSeparator; - } - - /// - /// The DecimalPlaces property replicates the one from the NumericUpDown control - /// - [ - DefaultValue(DATAGRIDVIEWNUMERICUPDOWNCELL_defaultDecimalPlaces) - ] - public int DecimalPlaces - { - get => decimalPlaces; - - set - { - if (value < 0 || value > 99) - throw new ArgumentOutOfRangeException( - "The DecimalPlaces property cannot be smaller than 0 or larger than 99."); - if (decimalPlaces != value) - { - SetDecimalPlaces(RowIndex, value); - OnCommonChange(); // Assure that the cell or column gets repainted and autosized if needed - } - } - } - - /// - /// Returns the current DataGridView EditingControl as a DataGridViewNumericUpDownEditingControl control - /// - private DataGridViewNumericUpDownEditingControl EditingNumericUpDown => - DataGridView.EditingControl as DataGridViewNumericUpDownEditingControl; - - /// - /// Define the type of the cell's editing control - /// - public override Type EditType => defaultEditType; // the type is DataGridViewNumericUpDownEditingControl - - /// - /// The Increment property replicates the one from the NumericUpDown control - /// - public decimal Increment - { - get => increment; - - set - { - if (value < (decimal) 0.0) - throw new ArgumentOutOfRangeException("The Increment property cannot be smaller than 0."); - SetIncrement(RowIndex, value); - // No call to OnCommonChange is needed since the increment value does not affect the rendering of the cell. - } - } - - /// - /// The Maximum property replicates the one from the NumericUpDown control - /// - public decimal Maximum - { - get => maximum; - - set - { - if (maximum != value) - { - SetMaximum(RowIndex, value); - OnCommonChange(); - } - } - } - - /// - /// The Minimum property replicates the one from the NumericUpDown control - /// - public decimal Minimum - { - get => minimum; - - set - { - if (minimum != value) - { - SetMinimum(RowIndex, value); - OnCommonChange(); - } - } - } - - /// - /// The ThousandsSeparator property replicates the one from the NumericUpDown control - /// - [ - DefaultValue(DATAGRIDVIEWNUMERICUPDOWNCELL_defaultThousandsSeparator) - ] - public bool ThousandsSeparator - { - get => thousandsSeparator; - - set - { - if (thousandsSeparator != value) - { - SetThousandsSeparator(RowIndex, value); - OnCommonChange(); - } - } - } - - /// - /// Returns the type of the cell's Value property - /// - public override Type ValueType - { - get - { - Type valueType = base.ValueType; - if (valueType != null) return valueType; - return defaultValueType; - } - } - - // Used in KeyEntersEditMode function - [DllImport("USER32.DLL", CharSet = CharSet.Auto)] - private static extern short VkKeyScan(char key); - - /// - /// Clones a DataGridViewNumericUpDownCell cell, copies all the custom properties. - /// - public override object Clone() - { - DataGridViewNumericUpDownCell dataGridViewCell = base.Clone() as DataGridViewNumericUpDownCell; - if (dataGridViewCell != null) - { - dataGridViewCell.DecimalPlaces = DecimalPlaces; - dataGridViewCell.Increment = Increment; - dataGridViewCell.Maximum = Maximum; - dataGridViewCell.Minimum = Minimum; - dataGridViewCell.ThousandsSeparator = ThousandsSeparator; - } - return dataGridViewCell; - } - - /// - /// Returns the provided value constrained to be within the min and max. - /// - private decimal Constrain(decimal value) - { - Debug.Assert(minimum <= maximum); - if (value < minimum) value = minimum; - if (value > maximum) value = maximum; - return value; - } - - /// - /// DetachEditingControl gets called by the DataGridView control when the editing session is ending - /// - [ - EditorBrowsable(EditorBrowsableState.Advanced) - ] - public override void DetachEditingControl() - { - DataGridView dataGridView = DataGridView; - if (dataGridView == null || dataGridView.EditingControl == null) - throw new InvalidOperationException("Cell is detached or its grid has no editing control."); - - NumericUpDown numericUpDown = dataGridView.EditingControl as NumericUpDown; - if (numericUpDown != null) - { - // Editing controls get recycled. Indeed, when a DataGridViewNumericUpDownCell cell gets edited - // after another DataGridViewNumericUpDownCell cell, the same editing control gets reused for - // performance reasons (to avoid an unnecessary control destruction and creation). - // Here the undo buffer of the TextBox inside the NumericUpDown control gets cleared to avoid - // interferences between the editing sessions. - TextBox textBox = numericUpDown.Controls[1] as TextBox; - if (textBox != null) textBox.ClearUndo(); - } - - base.DetachEditingControl(); - } - - /// - /// Adjusts the location and size of the editing control given the alignment characteristics of the cell - /// - private Rectangle GetAdjustedEditingControlBounds(Rectangle editingControlBounds, - DataGridViewCellStyle cellStyle) - { - // Add a 1 pixel padding on the left and right of the editing control - editingControlBounds.X += 1; - editingControlBounds.Width = Math.Max(0, editingControlBounds.Width - 2); - - // Adjust the vertical location of the editing control: - int preferredHeight = cellStyle.Font.Height + 3; - if (preferredHeight < editingControlBounds.Height) - switch (cellStyle.Alignment) - { - case DataGridViewContentAlignment.MiddleLeft: - case DataGridViewContentAlignment.MiddleCenter: - case DataGridViewContentAlignment.MiddleRight: - editingControlBounds.Y += (editingControlBounds.Height - preferredHeight) / 2; - break; - - case DataGridViewContentAlignment.BottomLeft: - case DataGridViewContentAlignment.BottomCenter: - case DataGridViewContentAlignment.BottomRight: - editingControlBounds.Y += editingControlBounds.Height - preferredHeight; - break; - } - - return editingControlBounds; - } - - /// - /// Customized implementation of the GetErrorIconBounds function in order to draw the potential - /// error icon next to the up/down buttons and not on top of them. - /// - protected override Rectangle GetErrorIconBounds(Graphics graphics, DataGridViewCellStyle cellStyle, - int rowIndex) - { - const int ButtonsWidth = 16; - - Rectangle errorIconBounds = base.GetErrorIconBounds(graphics, cellStyle, rowIndex); - if (DataGridView.RightToLeft == RightToLeft.Yes) - errorIconBounds.X = errorIconBounds.Left + ButtonsWidth; - else - errorIconBounds.X = errorIconBounds.Left - ButtonsWidth; - return errorIconBounds; - } - - /// - /// Customized implementation of the GetFormattedValue function in order to include the decimal and thousand separator - /// characters in the formatted representation of the cell value. - /// - protected override object GetFormattedValue(object value, - int rowIndex, - ref DataGridViewCellStyle cellStyle, - TypeConverter valueTypeConverter, - TypeConverter formattedValueTypeConverter, - DataGridViewDataErrorContexts context) - { - // By default, the base implementation converts the Decimal 1234.5 into the string "1234.5" - object formattedValue = base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, - formattedValueTypeConverter, context); - string formattedNumber = formattedValue as string; - if (!string.IsNullOrEmpty(formattedNumber) && value != null) - { - decimal unformattedDecimal = Convert.ToDecimal(value); - decimal formattedDecimal = Convert.ToDecimal(formattedNumber); - if (unformattedDecimal == formattedDecimal) - // The base implementation of GetFormattedValue (which triggers the CellFormatting event) did nothing else than - // the typical 1234.5 to "1234.5" conversion. But depending on the values of ThousandsSeparator and DecimalPlaces, - // this may not be the actual string displayed. The real formatted value may be "1,234.500" - return formattedDecimal.ToString((ThousandsSeparator ? "N" : "F") + DecimalPlaces); - } - return formattedValue; - } - - /// - /// Custom implementation of the GetPreferredSize function. This implementation uses the preferred size of the base - /// DataGridViewTextBoxCell cell and adds room for the up/down buttons. - /// - protected override Size GetPreferredSize(Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex, - Size constraintSize) - { - if (DataGridView == null) return new Size(-1, -1); - - Size preferredSize = base.GetPreferredSize(graphics, cellStyle, rowIndex, constraintSize); - if (constraintSize.Width == 0) - { - const int ButtonsWidth = 16; // Account for the width of the up/down buttons. - const int ButtonMargin = 8; // Account for some blank pixels between the text and buttons. - preferredSize.Width += ButtonsWidth + ButtonMargin; - } - return preferredSize; - } - - /// - /// Custom implementation of the InitializeEditingControl function. This function is called by the DataGridView control - /// at the beginning of an editing session. It makes sure that the properties of the NumericUpDown editing control are - /// set according to the cell properties. - /// - public override void InitializeEditingControl(int rowIndex, object initialFormattedValue, - DataGridViewCellStyle dataGridViewCellStyle) - { - base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle); - NumericUpDown numericUpDown = DataGridView.EditingControl as NumericUpDown; - if (numericUpDown != null) - { - numericUpDown.BorderStyle = BorderStyle.None; - numericUpDown.DecimalPlaces = DecimalPlaces; - numericUpDown.Increment = Increment; - numericUpDown.Maximum = Maximum; - numericUpDown.Minimum = Minimum; - numericUpDown.ThousandsSeparator = ThousandsSeparator; - string initialFormattedValueStr = initialFormattedValue as string; - if (initialFormattedValueStr == null) - numericUpDown.Text = string.Empty; - else - numericUpDown.Text = initialFormattedValueStr; - } - } - - /// - /// Custom implementation of the KeyEntersEditMode function. This function is called by the DataGridView control - /// to decide whether a keystroke must start an editing session or not. In this case, a new session is started when - /// a digit or negative sign key is hit. - /// - public override bool KeyEntersEditMode(KeyEventArgs e) - { - NumberFormatInfo numberFormatInfo = CultureInfo.CurrentCulture.NumberFormat; - Keys negativeSignKey = Keys.None; - string negativeSignStr = numberFormatInfo.NegativeSign; - if (!string.IsNullOrEmpty(negativeSignStr) && negativeSignStr.Length == 1) - negativeSignKey = (Keys) VkKeyScan(negativeSignStr[0]); - - if ((char.IsDigit((char) e.KeyCode) || - (e.KeyCode >= Keys.NumPad0 && e.KeyCode <= Keys.NumPad9) || - negativeSignKey == e.KeyCode || - Keys.Subtract == e.KeyCode) && - !e.Shift && !e.Alt && !e.Control) - return true; - return false; - } - - /// - /// Called when a cell characteristic that affects its rendering and/or preferred size has changed. - /// This implementation only takes care of repainting the cells. The DataGridView's autosizing methods - /// also need to be called in cases where some grid elements autosize. - /// - private void OnCommonChange() - { - if (DataGridView != null && !DataGridView.IsDisposed && !DataGridView.Disposing) - { - if (RowIndex == -1) - // Invalidate and autosize column - DataGridView.InvalidateColumn(ColumnIndex); - - // TODO: Add code to autosize the cell's column, the rows, the column headers - // and the row headers depending on their autosize settings. - // The DataGridView control does not expose a public method that takes care of this. - else - // The DataGridView control exposes a public method called UpdateCellValue - // that invalidates the cell so that it gets repainted and also triggers all - // the necessary autosizing: the cell's column and/or row, the column headers - // and the row headers are autosized depending on their autosize settings. - DataGridView.UpdateCellValue(ColumnIndex, RowIndex); - } - } - - /// - /// Determines whether this cell, at the given row index, shows the grid's editing control or not. - /// The row index needs to be provided as a parameter because this cell may be shared among multiple rows. - /// - private bool OwnsEditingNumericUpDown(int rowIndex) - { - if (rowIndex == -1 || DataGridView == null) return false; - DataGridViewNumericUpDownEditingControl numericUpDownEditingControl = - DataGridView.EditingControl as DataGridViewNumericUpDownEditingControl; - return numericUpDownEditingControl != null && rowIndex == - ((IDataGridViewEditingControl) numericUpDownEditingControl).EditingControlRowIndex; - } - - /// - /// Custom paints the cell. The base implementation of the DataGridViewTextBoxCell type is called first, - /// dropping the icon error and content foreground parts. Those two parts are painted by this custom implementation. - /// In this sample, the non-edited NumericUpDown control is painted by using a call to Control.DrawToBitmap. This is - /// an easy solution for painting controls but it's not necessarily the most performant. An alternative would be to - /// paint - /// the NumericUpDown control piece by piece (text and up/down buttons). - /// - protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, - DataGridViewElementStates cellState, - object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, - DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) - { - if (DataGridView == null) return; - - // First paint the borders and background of the cell. - base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, - cellStyle, advancedBorderStyle, - paintParts & ~(DataGridViewPaintParts.ErrorIcon | DataGridViewPaintParts.ContentForeground)); - - Point ptCurrentCell = DataGridView.CurrentCellAddress; - bool cellCurrent = ptCurrentCell.X == ColumnIndex && ptCurrentCell.Y == rowIndex; - bool cellEdited = cellCurrent && DataGridView.EditingControl != null; - - // If the cell is in editing mode, there is nothing else to paint - if (!cellEdited) - { - if (PartPainted(paintParts, DataGridViewPaintParts.ContentForeground)) - { - // Paint a NumericUpDown control - // Take the borders into account - Rectangle borderWidths = BorderWidths(advancedBorderStyle); - Rectangle valBounds = cellBounds; - valBounds.Offset(borderWidths.X, borderWidths.Y); - valBounds.Width -= borderWidths.Right; - valBounds.Height -= borderWidths.Bottom; - // Also take the padding into account - if (cellStyle.Padding != Padding.Empty) - { - if (DataGridView.RightToLeft == RightToLeft.Yes) - valBounds.Offset(cellStyle.Padding.Right, cellStyle.Padding.Top); - else - valBounds.Offset(cellStyle.Padding.Left, cellStyle.Padding.Top); - valBounds.Width -= cellStyle.Padding.Horizontal; - valBounds.Height -= cellStyle.Padding.Vertical; - } - // Determine the NumericUpDown control location - valBounds = GetAdjustedEditingControlBounds(valBounds, cellStyle); - - bool cellSelected = (cellState & DataGridViewElementStates.Selected) != 0; - - if (renderingBitmap.Width < valBounds.Width || - renderingBitmap.Height < valBounds.Height) - { - // The static bitmap is too small, a bigger one needs to be allocated. - renderingBitmap.Dispose(); - renderingBitmap = new Bitmap(valBounds.Width, valBounds.Height); - } - // Make sure the NumericUpDown control is parented to a visible control - if (paintingNumericUpDown.Parent == null || !paintingNumericUpDown.Parent.Visible) - paintingNumericUpDown.Parent = DataGridView; - // Set all the relevant properties - paintingNumericUpDown.TextAlign = TranslateAlignment(cellStyle.Alignment); - paintingNumericUpDown.DecimalPlaces = DecimalPlaces; - paintingNumericUpDown.ThousandsSeparator = ThousandsSeparator; - paintingNumericUpDown.Font = cellStyle.Font; - paintingNumericUpDown.Width = valBounds.Width; - paintingNumericUpDown.Height = valBounds.Height; - paintingNumericUpDown.RightToLeft = DataGridView.RightToLeft; - paintingNumericUpDown.Location = new Point(0, -paintingNumericUpDown.Height - 100); - paintingNumericUpDown.Text = formattedValue as string; - - Color backColor; - if (PartPainted(paintParts, DataGridViewPaintParts.SelectionBackground) && cellSelected) - backColor = cellStyle.SelectionBackColor; - else - backColor = cellStyle.BackColor; - if (PartPainted(paintParts, DataGridViewPaintParts.Background)) - { - if (backColor.A < 255) - // The NumericUpDown control does not support transparent back colors - backColor = Color.FromArgb(255, backColor); - paintingNumericUpDown.BackColor = backColor; - } - // Finally paint the NumericUpDown control - Rectangle srcRect = new Rectangle(0, 0, valBounds.Width, valBounds.Height); - if (srcRect.Width > 0 && srcRect.Height > 0) - { - paintingNumericUpDown.DrawToBitmap(renderingBitmap, srcRect); - graphics.DrawImage(renderingBitmap, new Rectangle(valBounds.Location, valBounds.Size), - srcRect, GraphicsUnit.Pixel); - } - } - if (PartPainted(paintParts, DataGridViewPaintParts.ErrorIcon)) - // Paint the potential error icon on top of the NumericUpDown control - base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, - cellStyle, advancedBorderStyle, DataGridViewPaintParts.ErrorIcon); - } - } - - /// - /// Little utility function called by the Paint function to see if a particular part needs to be painted. - /// - private static bool PartPainted(DataGridViewPaintParts paintParts, DataGridViewPaintParts paintPart) => - (paintParts & paintPart) != 0; - - /// - /// Custom implementation of the PositionEditingControl method called by the DataGridView control when it - /// needs to relocate and/or resize the editing control. - /// - public override void PositionEditingControl(bool setLocation, - bool setSize, - Rectangle cellBounds, - Rectangle cellClip, - DataGridViewCellStyle cellStyle, - bool singleVerticalBorderAdded, - bool singleHorizontalBorderAdded, - bool isFirstDisplayedColumn, - bool isFirstDisplayedRow) - { - Rectangle editingControlBounds = PositionEditingPanel(cellBounds, - cellClip, - cellStyle, - singleVerticalBorderAdded, - singleHorizontalBorderAdded, - isFirstDisplayedColumn, - isFirstDisplayedRow); - editingControlBounds = GetAdjustedEditingControlBounds(editingControlBounds, cellStyle); - DataGridView.EditingControl.Location = new Point(editingControlBounds.X, editingControlBounds.Y); - DataGridView.EditingControl.Size = new Size(editingControlBounds.Width, editingControlBounds.Height); - } - - /// - /// Utility function that sets a new value for the DecimalPlaces property of the cell. This function is used by - /// the cell and column DecimalPlaces property. The column uses this method instead of the DecimalPlaces - /// property for performance reasons. This way the column can invalidate the entire column at once instead of - /// invalidating each cell of the column individually. A row index needs to be provided as a parameter because - /// this cell may be shared among multiple rows. - /// - internal void SetDecimalPlaces(int rowIndex, int value) - { - Debug.Assert(value >= 0 && value <= 99); - decimalPlaces = value; - if (OwnsEditingNumericUpDown(rowIndex)) EditingNumericUpDown.DecimalPlaces = value; - } - - /// Utility function that sets a new value for the Increment property of the cell. This function is used by - /// the cell and column Increment property. A row index needs to be provided as a parameter because - /// this cell may be shared among multiple rows. - internal void SetIncrement(int rowIndex, decimal value) - { - Debug.Assert(value >= (decimal) 0.0); - increment = value; - if (OwnsEditingNumericUpDown(rowIndex)) EditingNumericUpDown.Increment = value; - } - - /// Utility function that sets a new value for the Maximum property of the cell. This function is used by - /// the cell and column Maximum property. The column uses this method instead of the Maximum - /// property for performance reasons. This way the column can invalidate the entire column at once instead of - /// invalidating each cell of the column individually. A row index needs to be provided as a parameter because - /// this cell may be shared among multiple rows. - internal void SetMaximum(int rowIndex, decimal value) - { - maximum = value; - if (minimum > maximum) minimum = maximum; - object cellValue = GetValue(rowIndex); - if (cellValue != null) - { - decimal currentValue = Convert.ToDecimal(cellValue); - decimal constrainedValue = Constrain(currentValue); - if (constrainedValue != currentValue) SetValue(rowIndex, constrainedValue); - } - Debug.Assert(maximum == value); - if (OwnsEditingNumericUpDown(rowIndex)) EditingNumericUpDown.Maximum = value; - } - - /// Utility function that sets a new value for the Minimum property of the cell. This function is used by - /// the cell and column Minimum property. The column uses this method instead of the Minimum - /// property for performance reasons. This way the column can invalidate the entire column at once instead of - /// invalidating each cell of the column individually. A row index needs to be provided as a parameter because - /// this cell may be shared among multiple rows. - internal void SetMinimum(int rowIndex, decimal value) - { - minimum = value; - if (minimum > maximum) maximum = value; - object cellValue = GetValue(rowIndex); - if (cellValue != null) - { - decimal currentValue = Convert.ToDecimal(cellValue); - decimal constrainedValue = Constrain(currentValue); - if (constrainedValue != currentValue) SetValue(rowIndex, constrainedValue); - } - Debug.Assert(minimum == value); - if (OwnsEditingNumericUpDown(rowIndex)) EditingNumericUpDown.Minimum = value; - } - - /// Utility function that sets a new value for the ThousandsSeparator property of the cell. This function is used by - /// the cell and column ThousandsSeparator property. The column uses this method instead of the ThousandsSeparator - /// property for performance reasons. This way the column can invalidate the entire column at once instead of - /// invalidating each cell of the column individually. A row index needs to be provided as a parameter because - /// this cell may be shared among multiple rows. - internal void SetThousandsSeparator(int rowIndex, bool value) - { - thousandsSeparator = value; - if (OwnsEditingNumericUpDown(rowIndex)) EditingNumericUpDown.ThousandsSeparator = value; - } - - /// - /// Returns a standard textual representation of the cell. - /// - public override string ToString() => "DataGridViewNumericUpDownCell { ColumnIndex=" + - ColumnIndex.ToString(CultureInfo.CurrentCulture) + ", RowIndex=" + - RowIndex.ToString(CultureInfo.CurrentCulture) + " }"; - - /// - /// Little utility function used by both the cell and column types to translate a DataGridViewContentAlignment value - /// into - /// a HorizontalAlignment value. - /// - internal static HorizontalAlignment TranslateAlignment(DataGridViewContentAlignment align) - { - if ((align & anyRight) != 0) - return HorizontalAlignment.Right; - if ((align & anyCenter) != 0) - return HorizontalAlignment.Center; - return HorizontalAlignment.Left; - } - } -} \ No newline at end of file diff --git a/GradeCalc/DataGridViewNumericUpDownColumn.cs b/GradeCalc/DataGridViewNumericUpDownColumn.cs deleted file mode 100644 index 6b6b834..0000000 --- a/GradeCalc/DataGridViewNumericUpDownColumn.cs +++ /dev/null @@ -1,270 +0,0 @@ -using System; -using System.ComponentModel; -using System.Globalization; -using System.Text; -using System.Windows.Forms; - -namespace GradeCalc -{ - /// - /// Custom column type dedicated to the DataGridViewNumericUpDownCell cell type. - /// - public class DataGridViewNumericUpDownColumn : DataGridViewColumn - { - /// - /// Constructor for the DataGridViewNumericUpDownColumn class. - /// - public DataGridViewNumericUpDownColumn() : base(new DataGridViewNumericUpDownCell()) - { - } - - /// - /// Represents the implicit cell that gets cloned when adding rows to the grid. - /// - [Browsable(false)] - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public override DataGridViewCell CellTemplate - { - get => base.CellTemplate; - set - { - DataGridViewNumericUpDownCell dataGridViewNumericUpDownCell = value as DataGridViewNumericUpDownCell; - if (value != null && dataGridViewNumericUpDownCell == null) - throw new InvalidCastException( - "Value provided for CellTemplate must be of type DataGridViewNumericUpDownElements.DataGridViewNumericUpDownCell or derive from it."); - base.CellTemplate = value; - } - } - - /// - /// Replicates the DecimalPlaces property of the DataGridViewNumericUpDownCell cell type. - /// - [Category("Appearance")] - [DefaultValue(DataGridViewNumericUpDownCell.DATAGRIDVIEWNUMERICUPDOWNCELL_defaultDecimalPlaces)] - [Description("Indicates the number of decimal places to display.")] - public int DecimalPlaces - { - get - { - if (NumericUpDownCellTemplate == null) - throw new InvalidOperationException( - "Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); - return NumericUpDownCellTemplate.DecimalPlaces; - } - set - { - if (NumericUpDownCellTemplate == null) - throw new InvalidOperationException( - "Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); - // Update the template cell so that subsequent cloned cells use the new value. - NumericUpDownCellTemplate.DecimalPlaces = value; - if (DataGridView != null) - { - // Update all the existing DataGridViewNumericUpDownCell cells in the column accordingly. - DataGridViewRowCollection dataGridViewRows = DataGridView.Rows; - int rowCount = dataGridViewRows.Count; - for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) - { - // Be careful not to unshare rows unnecessarily. - // This could have severe performance repercussions. - DataGridViewRow dataGridViewRow = dataGridViewRows.SharedRow(rowIndex); - DataGridViewNumericUpDownCell dataGridViewCell = - dataGridViewRow.Cells[Index] as DataGridViewNumericUpDownCell; - if (dataGridViewCell != null) - // Call the internal SetDecimalPlaces method instead of the property to avoid invalidation - // of each cell. The whole column is invalidated later in a single operation for better performance. - dataGridViewCell.SetDecimalPlaces(rowIndex, value); - } - DataGridView.InvalidateColumn(Index); - // TODO: Call the grid's autosizing methods to autosize the column, rows, column headers / row headers as needed. - } - } - } - - /// - /// Replicates the Increment property of the DataGridViewNumericUpDownCell cell type. - /// - [Category("Data")] - [Description("Indicates the amount to increment or decrement on each button click.")] - public decimal Increment - { - get - { - if (NumericUpDownCellTemplate == null) - throw new InvalidOperationException( - "Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); - return NumericUpDownCellTemplate.Increment; - } - set - { - if (NumericUpDownCellTemplate == null) - throw new InvalidOperationException( - "Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); - NumericUpDownCellTemplate.Increment = value; - if (DataGridView != null) - { - DataGridViewRowCollection dataGridViewRows = DataGridView.Rows; - int rowCount = dataGridViewRows.Count; - for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) - { - DataGridViewRow dataGridViewRow = dataGridViewRows.SharedRow(rowIndex); - DataGridViewNumericUpDownCell dataGridViewCell = - dataGridViewRow.Cells[Index] as DataGridViewNumericUpDownCell; - if (dataGridViewCell != null) dataGridViewCell.SetIncrement(rowIndex, value); - } - } - } - } - - /// - /// Replicates the Maximum property of the DataGridViewNumericUpDownCell cell type. - /// - [Category("Data")] - [Description("Indicates the maximum value for the numeric up-down cells.")] - [RefreshProperties(RefreshProperties.All)] - public decimal Maximum - { - get - { - if (NumericUpDownCellTemplate == null) - throw new InvalidOperationException( - "Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); - return NumericUpDownCellTemplate.Maximum; - } - set - { - if (NumericUpDownCellTemplate == null) - throw new InvalidOperationException( - "Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); - NumericUpDownCellTemplate.Maximum = value; - if (DataGridView != null) - { - DataGridViewRowCollection dataGridViewRows = DataGridView.Rows; - int rowCount = dataGridViewRows.Count; - for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) - { - DataGridViewRow dataGridViewRow = dataGridViewRows.SharedRow(rowIndex); - DataGridViewNumericUpDownCell dataGridViewCell = - dataGridViewRow.Cells[Index] as DataGridViewNumericUpDownCell; - if (dataGridViewCell != null) dataGridViewCell.SetMaximum(rowIndex, value); - } - DataGridView.InvalidateColumn(Index); - // TODO: This column and/or grid rows may need to be autosized depending on their - // autosize settings. Call the autosizing methods to autosize the column, rows, - // column headers / row headers as needed. - } - } - } - - /// - /// Replicates the Minimum property of the DataGridViewNumericUpDownCell cell type. - /// - [Category("Data")] - [Description("Indicates the minimum value for the numeric up-down cells.")] - [RefreshProperties(RefreshProperties.All)] - public decimal Minimum - { - get - { - if (NumericUpDownCellTemplate == null) - throw new InvalidOperationException( - "Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); - return NumericUpDownCellTemplate.Minimum; - } - set - { - if (NumericUpDownCellTemplate == null) - throw new InvalidOperationException( - "Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); - NumericUpDownCellTemplate.Minimum = value; - if (DataGridView != null) - { - DataGridViewRowCollection dataGridViewRows = DataGridView.Rows; - int rowCount = dataGridViewRows.Count; - for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) - { - DataGridViewRow dataGridViewRow = dataGridViewRows.SharedRow(rowIndex); - DataGridViewNumericUpDownCell dataGridViewCell = - dataGridViewRow.Cells[Index] as DataGridViewNumericUpDownCell; - if (dataGridViewCell != null) dataGridViewCell.SetMinimum(rowIndex, value); - } - DataGridView.InvalidateColumn(Index); - // TODO: This column and/or grid rows may need to be autosized depending on their - // autosize settings. Call the autosizing methods to autosize the column, rows, - // column headers / row headers as needed. - } - } - } - - /// - /// Replicates the ThousandsSeparator property of the DataGridViewNumericUpDownCell cell type. - /// - [Category("Data")] - [DefaultValue(DataGridViewNumericUpDownCell.DATAGRIDVIEWNUMERICUPDOWNCELL_defaultThousandsSeparator)] - [Description("Indicates whether the thousands separator will be inserted between every three decimal digits.")] - public bool ThousandsSeparator - { - get - { - if (NumericUpDownCellTemplate == null) - throw new InvalidOperationException( - "Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); - return NumericUpDownCellTemplate.ThousandsSeparator; - } - set - { - if (NumericUpDownCellTemplate == null) - throw new InvalidOperationException( - "Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); - NumericUpDownCellTemplate.ThousandsSeparator = value; - if (DataGridView != null) - { - DataGridViewRowCollection dataGridViewRows = DataGridView.Rows; - int rowCount = dataGridViewRows.Count; - for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) - { - DataGridViewRow dataGridViewRow = dataGridViewRows.SharedRow(rowIndex); - DataGridViewNumericUpDownCell dataGridViewCell = - dataGridViewRow.Cells[Index] as DataGridViewNumericUpDownCell; - if (dataGridViewCell != null) dataGridViewCell.SetThousandsSeparator(rowIndex, value); - } - DataGridView.InvalidateColumn(Index); - // TODO: This column and/or grid rows may need to be autosized depending on their - // autosize settings. Call the autosizing methods to autosize the column, rows, - // column headers / row headers as needed. - } - } - } - - /// - /// Small utility function that returns the template cell as a DataGridViewNumericUpDownCell - /// - private DataGridViewNumericUpDownCell NumericUpDownCellTemplate => (DataGridViewNumericUpDownCell) CellTemplate; - - /// Indicates whether the Increment property should be persisted. - private bool ShouldSerializeIncrement() => - !Increment.Equals(DataGridViewNumericUpDownCell.DATAGRIDVIEWNUMERICUPDOWNCELL_defaultIncrement); - - /// Indicates whether the Maximum property should be persisted. - private bool ShouldSerializeMaximum() => - !Maximum.Equals(DataGridViewNumericUpDownCell.DATAGRIDVIEWNUMERICUPDOWNCELL_defaultMaximum); - - /// Indicates whether the Maximum property should be persisted. - private bool ShouldSerializeMinimum() => - !Minimum.Equals(DataGridViewNumericUpDownCell.DATAGRIDVIEWNUMERICUPDOWNCELL_defaultMinimum); - - /// - /// Returns a standard compact string representation of the column. - /// - public override string ToString() - { - StringBuilder sb = new StringBuilder(100); - sb.Append("DataGridViewNumericUpDownColumn { Name="); - sb.Append(Name); - sb.Append(", Index="); - sb.Append(Index.ToString(CultureInfo.CurrentCulture)); - sb.Append(" }"); - return sb.ToString(); - } - } -} \ No newline at end of file diff --git a/GradeCalc/DataGridViewNumericUpDownEditingControl.cs b/GradeCalc/DataGridViewNumericUpDownEditingControl.cs deleted file mode 100644 index cb5188a..0000000 --- a/GradeCalc/DataGridViewNumericUpDownEditingControl.cs +++ /dev/null @@ -1,285 +0,0 @@ -using System; -using System.Drawing; -using System.Globalization; -using System.Runtime.InteropServices; -using System.Windows.Forms; - -namespace GradeCalc -{ - /// - /// Defines the editing control for the DataGridViewNumericUpDownCell custom cell type. - /// - internal class DataGridViewNumericUpDownEditingControl : NumericUpDown, IDataGridViewEditingControl - { - // The grid that owns this editing control - private DataGridView dataGridView; - - // Stores the row index in which the editing control resides - - // Stores whether the editing control's value has changed or not - private bool valueChanged; - - /// - /// Constructor of the editing control class - /// - // The editing control must not be part of the tabbing loop - public DataGridViewNumericUpDownEditingControl() => TabStop = false; - - // Beginning of the IDataGridViewEditingControl interface implementation - - /// - /// Property which caches the grid that uses this editing control - /// - public virtual DataGridView EditingControlDataGridView - { - get => dataGridView; - set => dataGridView = value; - } - - /// - /// Property which represents the current formatted value of the editing control - /// - public virtual object EditingControlFormattedValue - { - get => GetEditingControlFormattedValue(DataGridViewDataErrorContexts.Formatting); - set => Text = (string) value; - } - - /// - /// Property which represents the row in which the editing control resides - /// - public virtual int EditingControlRowIndex { get; set; } - - /// - /// Property which indicates whether the value of the editing control has changed or not - /// - public virtual bool EditingControlValueChanged - { - get => valueChanged; - set => valueChanged = value; - } - - /// - /// Property which determines which cursor must be used for the editing panel, - /// i.e. the parent of the editing control. - /// - public virtual Cursor EditingPanelCursor => Cursors.Default; - - /// - /// Property which indicates whether the editing control needs to be repositioned - /// when its value changes. - /// - public virtual bool RepositionEditingControlOnValueChange => false; - - /// - /// Method called by the grid before the editing control is shown so it can adapt to the - /// provided cell style. - /// - public virtual void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) - { - Font = dataGridViewCellStyle.Font; - if (dataGridViewCellStyle.BackColor.A < 255) - { - // The NumericUpDown control does not support transparent back colors - Color opaqueBackColor = Color.FromArgb(255, dataGridViewCellStyle.BackColor); - BackColor = opaqueBackColor; - dataGridView.EditingPanel.BackColor = opaqueBackColor; - } - else - { - BackColor = dataGridViewCellStyle.BackColor; - } - ForeColor = dataGridViewCellStyle.ForeColor; - TextAlign = DataGridViewNumericUpDownCell.TranslateAlignment(dataGridViewCellStyle.Alignment); - } - - /// - /// Method called by the grid on keystrokes to determine if the editing control is - /// interested in the key or not. - /// - public virtual bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) - { - switch (keyData & Keys.KeyCode) - { - case Keys.Right: - { - TextBox textBox = Controls[1] as TextBox; - if (textBox != null) - // If the end of the selection is at the end of the string, - // let the DataGridView treat the key message - if ((RightToLeft == RightToLeft.No && - !(textBox.SelectionLength == 0 && textBox.SelectionStart == textBox.Text.Length)) || - (RightToLeft == RightToLeft.Yes && - !(textBox.SelectionLength == 0 && textBox.SelectionStart == 0))) - return true; - break; - } - - case Keys.Left: - { - TextBox textBox = Controls[1] as TextBox; - if (textBox != null) - // If the end of the selection is at the begining of the string - // or if the entire text is selected and we did not start editing, - // send this character to the dataGridView, else process the key message - if ((RightToLeft == RightToLeft.No && - !(textBox.SelectionLength == 0 && textBox.SelectionStart == 0)) || - (RightToLeft == RightToLeft.Yes && - !(textBox.SelectionLength == 0 && textBox.SelectionStart == textBox.Text.Length))) - return true; - break; - } - - case Keys.Down: - // If the current value hasn't reached its minimum yet, handle the key. Otherwise let - // the grid handle it. - if (Value > Minimum) return true; - break; - - case Keys.Up: - // If the current value hasn't reached its maximum yet, handle the key. Otherwise let - // the grid handle it. - if (Value < Maximum) return true; - break; - - case Keys.Home: - case Keys.End: - { - // Let the grid handle the key if the entire text is selected. - TextBox textBox = Controls[1] as TextBox; - if (textBox != null) - if (textBox.SelectionLength != textBox.Text.Length) - return true; - break; - } - - case Keys.Delete: - { - // Let the grid handle the key if the carret is at the end of the text. - TextBox textBox = Controls[1] as TextBox; - if (textBox != null) - if (textBox.SelectionLength > 0 || - textBox.SelectionStart < textBox.Text.Length) - return true; - break; - } - } - return !dataGridViewWantsInputKey; - } - - /// - /// Returns the current value of the editing control. - /// - public virtual object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) - { - bool userEdit = UserEdit; - try - { - // Prevent the Value from being set to Maximum or Minimum when the cell is being painted. - UserEdit = (context & DataGridViewDataErrorContexts.Display) == 0; - return Value.ToString((ThousandsSeparator ? "N" : "F") + DecimalPlaces); - } - finally - { - UserEdit = userEdit; - } - } - - /// - /// Called by the grid to give the editing control a chance to prepare itself for - /// the editing session. - /// - public virtual void PrepareEditingControlForEdit(bool selectAll) - { - TextBox textBox = Controls[1] as TextBox; - if (textBox != null) - { - if (selectAll) - textBox.SelectAll(); - else - // Do not select all the text, but - // position the caret at the end of the text - textBox.SelectionStart = textBox.Text.Length; - } - } - - // Needed to forward keyboard messages to the child TextBox control. - [DllImport("USER32.DLL", CharSet = CharSet.Auto)] - private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); - - // End of the IDataGridViewEditingControl interface implementation - - /// - /// Small utility function that updates the local dirty state and - /// notifies the grid of the value change. - /// - private void NotifyDataGridViewOfValueChange() - { - if (!valueChanged) - { - valueChanged = true; - dataGridView.NotifyCurrentCellDirty(true); - } - } - - /// - /// Listen to the KeyPress notification to know when the value changed, and - /// notify the grid of the change. - /// - protected override void OnKeyPress(KeyPressEventArgs e) - { - base.OnKeyPress(e); - - // The value changes when a digit, the decimal separator, the group separator or - // the negative sign is pressed. - bool notifyValueChange = false; - if (char.IsDigit(e.KeyChar)) - { - notifyValueChange = true; - } - else - { - NumberFormatInfo numberFormatInfo = CultureInfo.CurrentCulture.NumberFormat; - string decimalSeparatorStr = numberFormatInfo.NumberDecimalSeparator; - string groupSeparatorStr = numberFormatInfo.NumberGroupSeparator; - string negativeSignStr = numberFormatInfo.NegativeSign; - if (!string.IsNullOrEmpty(decimalSeparatorStr) && decimalSeparatorStr.Length == 1) - notifyValueChange = decimalSeparatorStr[0] == e.KeyChar; - if (!notifyValueChange && !string.IsNullOrEmpty(groupSeparatorStr) && groupSeparatorStr.Length == 1) - notifyValueChange = groupSeparatorStr[0] == e.KeyChar; - if (!notifyValueChange && !string.IsNullOrEmpty(negativeSignStr) && negativeSignStr.Length == 1) - notifyValueChange = negativeSignStr[0] == e.KeyChar; - } - - if (notifyValueChange) - // Let the DataGridView know about the value change - NotifyDataGridViewOfValueChange(); - } - - /// - /// Listen to the ValueChanged notification to forward the change to the grid. - /// - protected override void OnValueChanged(EventArgs e) - { - base.OnValueChanged(e); - if (Focused) - // Let the DataGridView know about the value change - NotifyDataGridViewOfValueChange(); - } - - /// - /// A few keyboard messages need to be forwarded to the inner textbox of the - /// NumericUpDown control so that the first character pressed appears in it. - /// - protected override bool ProcessKeyEventArgs(ref Message m) - { - TextBox textBox = Controls[1] as TextBox; - if (textBox != null) - { - SendMessage(textBox.Handle, m.Msg, m.WParam, m.LParam); - return true; - } - return base.ProcessKeyEventArgs(ref m); - } - } -} \ No newline at end of file diff --git a/GradeCalc/GradeCalc.csproj b/GradeCalc/GradeCalc.csproj index 4f7307b..d61c0cf 100644 --- a/GradeCalc/GradeCalc.csproj +++ b/GradeCalc/GradeCalc.csproj @@ -1,155 +1,20 @@ - - - - + - Debug - AnyCPU - {D5948BBB-1F03-497A-A2BA-DD1E6F54A2A8} + netcoreapp3.1 WinExe - GradeCalc - GradeCalc - v4.6.1 - 512 - true - true - - - - publish\ - true - Disk - false - Foreground - 7 - Days - false - false - true - 0 - 1.0.0.%2a - false - false - true - - - AnyCPU - true - full - false - bin\Debug\ - DEBUG;TRACE - prompt - 4 - - - AnyCPU - none - true - bin\Release\ - TRACE - prompt - 4 + false + true + false - app.manifest + if exist "$(SolutionDir)Data\pkgtool.exe" ($(SolutionDir)Data\pkgtool.exe build --noLogo --binDir .) else if exist "%appdata%\UpTool2\Apps\0e35d154-d0d3-45e0-b080-62f521263a44\app\pkgtool.exe" ("%appdata%\UpTool2\Apps\0e35d154-d0d3-45e0-b080-62f521263a44\app\pkgtool.exe" build --noLogo --binDir .) else echo Cound not find Package build tools, skipping - - ..\packages\Antlr4.Runtime.4.6.6\lib\net45\Antlr4.Runtime.dll - - - ..\packages\EPPlus.4.5.3.3\lib\net40\EPPlus.dll - True - - - ..\packages\NCalc2.2.1.0\lib\net46\NCalc2.dll - - - - - - - - - - - - - - - + + + + + + - - - - - Component - - - Form - - - MainForm.cs - - - - - - MainForm.cs - - - ResXFileCodeGenerator - Resources.Designer.cs - Designer - - - True - Resources.resx - True - - - - - SettingsSingleFileGenerator - Settings.Designer.cs - - - True - Settings.settings - True - - - - - - - - False - Microsoft .NET Framework 4.6.1 %28x86 and x64%29 - true - - - False - .NET Framework 3.5 SP1 - false - - - - - cd "$(SolutionDir)" -if $(ConfigurationName)==Release ( -C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe PostBuild.cs /r:System.IO.Compression.FileSystem.dll -PostBuild "$(TargetDir)\" "$(TargetFileName)" -del PostBuild.exe -) - - - - This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - - - \ No newline at end of file diff --git a/GradeCalc/MainForm.Designer.cs b/GradeCalc/MainForm.Designer.cs index 02966af..ed4012c 100644 --- a/GradeCalc/MainForm.Designer.cs +++ b/GradeCalc/MainForm.Designer.cs @@ -31,31 +31,34 @@ this.dataGridView = new System.Windows.Forms.DataGridView(); this.calcButton = new System.Windows.Forms.Button(); this.configPanel = new System.Windows.Forms.Panel(); + this.saveButton = new System.Windows.Forms.Button(); + this.algorithmLabel = new System.Windows.Forms.Label(); + this.tasksLabel = new System.Windows.Forms.Label(); this.algorithmBox = new System.Windows.Forms.ComboBox(); this.tasksNum = new System.Windows.Forms.NumericUpDown(); - this.tasksLabel = new System.Windows.Forms.Label(); - this.algorithmLabel = new System.Windows.Forms.Label(); - this.saveButton = new System.Windows.Forms.Button(); - ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).BeginInit(); + ((System.ComponentModel.ISupportInitialize) (this.dataGridView)).BeginInit(); this.configPanel.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.tasksNum)).BeginInit(); + ((System.ComponentModel.ISupportInitialize) (this.tasksNum)).BeginInit(); this.SuspendLayout(); // // dataGridView // - this.dataGridView.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dataGridView.ColumnHeadersHeightSizeMode = + System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; this.dataGridView.Dock = System.Windows.Forms.DockStyle.Fill; this.dataGridView.Location = new System.Drawing.Point(0, 0); this.dataGridView.Name = "dataGridView"; - this.dataGridView.Size = new System.Drawing.Size(696, 274); + this.dataGridView.Size = new System.Drawing.Size(812, 316); this.dataGridView.TabIndex = 0; // // calcButton // - this.calcButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.calcButton.Location = new System.Drawing.Point(12, 6); + this.calcButton.Anchor = + ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Bottom | + System.Windows.Forms.AnchorStyles.Left))); + this.calcButton.Location = new System.Drawing.Point(14, 7); this.calcButton.Name = "calcButton"; - this.calcButton.Size = new System.Drawing.Size(100, 23); + this.calcButton.Size = new System.Drawing.Size(117, 27); this.calcButton.TabIndex = 1; this.calcButton.Text = "Calculate Grades"; this.calcButton.UseVisualStyleBackColor = true; @@ -70,98 +73,93 @@ this.configPanel.Controls.Add(this.tasksNum); this.configPanel.Controls.Add(this.calcButton); this.configPanel.Dock = System.Windows.Forms.DockStyle.Bottom; - this.configPanel.Location = new System.Drawing.Point(0, 274); + this.configPanel.Location = new System.Drawing.Point(0, 316); this.configPanel.Name = "configPanel"; - this.configPanel.Size = new System.Drawing.Size(696, 37); + this.configPanel.Size = new System.Drawing.Size(812, 43); this.configPanel.TabIndex = 2; // - // algorithmBox - // - this.algorithmBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left) - | System.Windows.Forms.AnchorStyles.Right))); - this.algorithmBox.FormattingEnabled = true; - this.algorithmBox.Items.AddRange(new object[] { - "score / maxScore", - "Pow(score / maxScore, 0.8)", - "Pow(score / maxScore, 1.2)"}); - this.algorithmBox.Location = new System.Drawing.Point(357, 8); - this.algorithmBox.Name = "algorithmBox"; - this.algorithmBox.Size = new System.Drawing.Size(309, 21); - this.algorithmBox.TabIndex = 3; - this.algorithmBox.Text = "score / maxScore"; - // - // tasksNum - // - this.tasksNum.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.tasksNum.Location = new System.Drawing.Point(163, 9); - this.tasksNum.Maximum = new decimal(new int[] { - 50, - 0, - 0, - 0}); - this.tasksNum.Minimum = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.tasksNum.Name = "tasksNum"; - this.tasksNum.Size = new System.Drawing.Size(120, 20); - this.tasksNum.TabIndex = 2; - this.tasksNum.Value = new decimal(new int[] { - 1, - 0, - 0, - 0}); - this.tasksNum.ValueChanged += new System.EventHandler(this.tasksNum_ValueChanged); - // - // tasksLabel - // - this.tasksLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.tasksLabel.AutoSize = true; - this.tasksLabel.Location = new System.Drawing.Point(118, 11); - this.tasksLabel.Name = "tasksLabel"; - this.tasksLabel.Size = new System.Drawing.Size(39, 13); - this.tasksLabel.TabIndex = 4; - this.tasksLabel.Text = "Tasks:"; - // - // algorithmLabel - // - this.algorithmLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left))); - this.algorithmLabel.AutoSize = true; - this.algorithmLabel.Location = new System.Drawing.Point(298, 11); - this.algorithmLabel.Name = "algorithmLabel"; - this.algorithmLabel.Size = new System.Drawing.Size(53, 13); - this.algorithmLabel.TabIndex = 5; - this.algorithmLabel.Text = "Algorithm:"; - // // saveButton // - this.saveButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); - this.saveButton.Location = new System.Drawing.Point(670, 6); + this.saveButton.Anchor = + ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Bottom | + System.Windows.Forms.AnchorStyles.Right))); + this.saveButton.Location = new System.Drawing.Point(782, 7); this.saveButton.Name = "saveButton"; - this.saveButton.Size = new System.Drawing.Size(23, 23); + this.saveButton.Size = new System.Drawing.Size(27, 27); this.saveButton.TabIndex = 6; this.saveButton.Text = "💾"; this.saveButton.UseVisualStyleBackColor = true; this.saveButton.Click += new System.EventHandler(this.saveButton_Click); // + // algorithmLabel + // + this.algorithmLabel.Anchor = + ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Bottom | + System.Windows.Forms.AnchorStyles.Left))); + this.algorithmLabel.AutoSize = true; + this.algorithmLabel.Location = new System.Drawing.Point(348, 13); + this.algorithmLabel.Name = "algorithmLabel"; + this.algorithmLabel.Size = new System.Drawing.Size(64, 15); + this.algorithmLabel.TabIndex = 5; + this.algorithmLabel.Text = "Algorithm:"; + // + // tasksLabel + // + this.tasksLabel.Anchor = + ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Bottom | + System.Windows.Forms.AnchorStyles.Left))); + this.tasksLabel.AutoSize = true; + this.tasksLabel.Location = new System.Drawing.Point(138, 13); + this.tasksLabel.Name = "tasksLabel"; + this.tasksLabel.Size = new System.Drawing.Size(37, 15); + this.tasksLabel.TabIndex = 4; + this.tasksLabel.Text = "Tasks:"; + // + // algorithmBox + // + this.algorithmBox.Anchor = + ((System.Windows.Forms.AnchorStyles) (((System.Windows.Forms.AnchorStyles.Bottom | + System.Windows.Forms.AnchorStyles.Left) | + System.Windows.Forms.AnchorStyles.Right))); + this.algorithmBox.FormattingEnabled = true; + this.algorithmBox.Items.AddRange(new object[] + {"score / maxScore", "Pow(score / maxScore, 0.8)", "Pow(score / maxScore, 1.2)"}); + this.algorithmBox.Location = new System.Drawing.Point(416, 9); + this.algorithmBox.Name = "algorithmBox"; + this.algorithmBox.Size = new System.Drawing.Size(360, 23); + this.algorithmBox.TabIndex = 3; + this.algorithmBox.Text = "score / maxScore"; + // + // tasksNum + // + this.tasksNum.Anchor = + ((System.Windows.Forms.AnchorStyles) ((System.Windows.Forms.AnchorStyles.Bottom | + System.Windows.Forms.AnchorStyles.Left))); + this.tasksNum.Location = new System.Drawing.Point(190, 10); + this.tasksNum.Maximum = new decimal(new int[] {50, 0, 0, 0}); + this.tasksNum.Minimum = new decimal(new int[] {1, 0, 0, 0}); + this.tasksNum.Name = "tasksNum"; + this.tasksNum.Size = new System.Drawing.Size(140, 23); + this.tasksNum.TabIndex = 2; + this.tasksNum.Value = new decimal(new int[] {1, 0, 0, 0}); + this.tasksNum.ValueChanged += new System.EventHandler(this.tasksNum_ValueChanged); + // // MainForm // - this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; - this.ClientSize = new System.Drawing.Size(696, 311); + this.ClientSize = new System.Drawing.Size(812, 359); this.Controls.Add(this.dataGridView); this.Controls.Add(this.configPanel); - this.MinimumSize = new System.Drawing.Size(504, 156); + this.MinimumSize = new System.Drawing.Size(585, 174); this.Name = "MainForm"; this.ShowIcon = false; this.Text = "GradeCalc"; - ((System.ComponentModel.ISupportInitialize)(this.dataGridView)).EndInit(); + ((System.ComponentModel.ISupportInitialize) (this.dataGridView)).EndInit(); this.configPanel.ResumeLayout(false); this.configPanel.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.tasksNum)).EndInit(); + ((System.ComponentModel.ISupportInitialize) (this.tasksNum)).EndInit(); this.ResumeLayout(false); - } #endregion diff --git a/GradeCalc/MainForm.cs b/GradeCalc/MainForm.cs index 46dbe4f..dca210a 100644 --- a/GradeCalc/MainForm.cs +++ b/GradeCalc/MainForm.cs @@ -2,106 +2,104 @@ using System.Collections.Generic; using System.ComponentModel; using System.Drawing; +using System.Globalization; using System.IO; using System.Linq; using System.Windows.Forms; +using CC_Functions.Misc; using NCalc2; using OfficeOpenXml; using OfficeOpenXml.Style; +using LicenseContext = OfficeOpenXml.LicenseContext; namespace GradeCalc { public partial class MainForm : Form { - private readonly DataGridViewTextBoxColumn gradeColumn; - private readonly DataGridViewTextBoxColumn nameColumn; + private readonly DataGridViewTextBoxColumn _gradeColumn; + private readonly DataGridViewTextBoxColumn _nameColumn; private readonly List - taskColumns = new List(); + _taskColumns = new List(); public MainForm() { InitializeComponent(); - nameColumn = new DataGridViewTextBoxColumn(); - nameColumn.HeaderText = "Name"; - nameColumn.Name = "Name"; - dataGridView.Columns.Add(nameColumn); - gradeColumn = new DataGridViewTextBoxColumn(); - gradeColumn.HeaderText = "Grade"; - gradeColumn.Name = "Grade"; - gradeColumn.ReadOnly = true; - dataGridView.Columns.Add(gradeColumn); + _nameColumn = new DataGridViewTextBoxColumn {HeaderText = "Name", Name = "Name"}; + dataGridView.Columns.Add(_nameColumn); + _gradeColumn = new DataGridViewTextBoxColumn {HeaderText = "Grade", Name = "Grade", ReadOnly = true}; + dataGridView.Columns.Add(_gradeColumn); tasksNum_ValueChanged(null, null); } - private int round(double val) => (int) Math.Round(val); + private static int Round(double val) => (int) Math.Round(val); - private Color getColor(double x, double max) => - Color.FromArgb(round(255 * (1 - (x / max))), round(255 * (x / max)), 0); + private static Color GetColor(double x, double max) => + Color.FromArgb(Round(255 * (1 - (x / max))), Round(255 * (x / max)), 0); private void calcButton_Click(object sender, EventArgs e) { foreach (DataGridViewRow row in dataGridView.Rows) { - row.Cells[nameColumn.Name].Style.BackColor = Color.White; - DataGridViewTextBoxCell gradeCell = (DataGridViewTextBoxCell) row.Cells[gradeColumn.Name]; + row.Cells[_nameColumn.Name].Style.BackColor = Color.White; + DataGridViewTextBoxCell gradeCell = (DataGridViewTextBoxCell) row.Cells[_gradeColumn.Name]; try { Expression ex = new Expression(algorithmBox.Text); decimal maxScore = 0; decimal totalScore = 0; - taskColumns.ForEach(s => + _taskColumns.ForEach(s => { DataGridViewNumericUpDownCell cell = (DataGridViewNumericUpDownCell) row.Cells[s.Name]; - if (!string.IsNullOrWhiteSpace((string) cell.FormattedValue)) - { - maxScore += cell.Maximum; - totalScore += decimal.Parse((string) cell.FormattedValue); - ex.Parameters["score"] = decimal.Parse((string) cell.FormattedValue); - ex.Parameters["maxScore"] = cell.Maximum; - cell.Style.BackColor = getColor((float) NCalcDoubleParser.Parse(ex.Evaluate()), 1); - } + if (string.IsNullOrWhiteSpace((string) cell.FormattedValue)) return; + maxScore += cell.Maximum; + totalScore += decimal.Parse((string) cell.FormattedValue); + ex.Parameters["score"] = decimal.Parse((string) cell.FormattedValue); + ex.Parameters["maxScore"] = cell.Maximum; + cell.Style.BackColor = GetColor((float) NCalcDoubleParser.Parse(ex.Evaluate()), 1); }); ex.Parameters["score"] = (double) totalScore; ex.Parameters["maxScore"] = (double) maxScore; double grade = 6 - (NCalcDoubleParser.Parse(ex.Evaluate()) * 5); - gradeCell.Value = (grade.ToString().Length > 13 ? grade.ToString().Remove(13) : grade.ToString()) + - " " + texGrade(grade); - gradeCell.Style.BackColor = getColor(grade - 1, 5); + gradeCell.Value = (grade.ToString(CultureInfo.InvariantCulture).Length > 13 + ? grade.ToString(CultureInfo.InvariantCulture).Remove(13) + : grade.ToString(CultureInfo.InvariantCulture)) + + " " + TexGrade(grade); + gradeCell.Style.BackColor = GetColor(grade - 1, 5); } - catch (Exception e1) + catch (Exception) { gradeCell.Value = ""; } } - dataGridView.Sort(nameColumn, ListSortDirection.Ascending); + dataGridView.Sort(_nameColumn, ListSortDirection.Ascending); } private void tasksNum_ValueChanged(object sender, EventArgs e) { - while (tasksNum.Value < taskColumns.Count) + while (tasksNum.Value < _taskColumns.Count) { - DataGridViewNumericUpDownColumn col = taskColumns[taskColumns.Count - 1]; + DataGridViewNumericUpDownColumn col = _taskColumns[_taskColumns.Count - 1]; dataGridView.Columns.Remove(col); - taskColumns.Remove(col); + _taskColumns.Remove(col); col.Dispose(); } - while (tasksNum.Value > taskColumns.Count) + while (tasksNum.Value > _taskColumns.Count) { - DataGridViewNumericUpDownColumn clm = new DataGridViewNumericUpDownColumn(); - clm.Minimum = 0; - clm.Maximum = 10; - clm.Name = "Task " + (taskColumns.Count + 1); + DataGridViewNumericUpDownColumn clm = new DataGridViewNumericUpDownColumn + { + Minimum = 0, Maximum = 10, Name = "Task " + (_taskColumns.Count + 1) + }; dataGridView.Columns.Add(clm); - taskColumns.Add(clm); + _taskColumns.Add(clm); } - gradeColumn.DisplayIndex = dataGridView.Columns.Count - 1; + _gradeColumn.DisplayIndex = dataGridView.Columns.Count - 1; } - private string texGrade(double g) + private static string TexGrade(double g) { - double gGrade = new[] {-0.5, 0, 0.5}.OrderBy(x => Math.Abs((x - (g - round(g))) + 1)).First(); - return (char) (('A' + round(g)) - 1) + + double gGrade = new[] {-0.5, 0, 0.5}.OrderBy(x => Math.Abs((x - (g - Round(g))) + 1)).First(); + return (char) (('A' + Round(g)) - 1) + (g == 1 || gGrade == -0.5 ? "+" : g == 6 || gGrade == 0.5 ? "-" : ""); } @@ -111,38 +109,29 @@ namespace GradeCalc { Filter = "Excel Spreadsheet|*.xlst" }; - if (dialog.ShowDialog() == DialogResult.OK) - using (ExcelPackage excel = new ExcelPackage()) + if (dialog.ShowDialog() != DialogResult.OK) return; + ExcelPackage.LicenseContext = LicenseContext.NonCommercial; + using ExcelPackage excel = new ExcelPackage(); + ExcelWorksheet worksheet = excel.Workbook.Worksheets.Add("Worksheet1"); + List headerRow = new List + { + dataGridView.Columns.OfType().Select(s => s.HeaderText).ToArray() + }; + string headerRange = "A1:" + char.ConvertFromUtf32(headerRow[0].Length + 64) + "1"; + worksheet.Cells[headerRange].LoadFromArrays(headerRow); + dataGridView.Rows.OfType() + .Reverse().Skip(1).Reverse().ToList().ForEach(s => { - ExcelWorksheet worksheet = excel.Workbook.Worksheets.Add("Worksheet1"); - List headerRow = new List + foreach (DataGridViewCell cell in s.Cells) { - dataGridView.Columns.OfType().Select(s => s.HeaderText).ToArray() - }; - string headerRange = "A1:" + char.ConvertFromUtf32(headerRow[0].Length + 64) + "1"; - ExcelRangeBase headers = worksheet.Cells[headerRange].LoadFromArrays(headerRow); - headers.Style.Font.Bold = true; - headers.Style.Font.Size = 14; - /*worksheet.Cells[2, 1].LoadFromArrays(dataGridView.Rows.OfType() - .Reverse().Skip(1).Reverse() - .Select(s => s.Cells.OfType() - .Select(t => t.Value.ToString()) - .ToArray() - ));*/ - dataGridView.Rows.OfType() - .Reverse().Skip(1).Reverse().ToList().ForEach(s => - { - foreach (DataGridViewCell cell in s.Cells) - { - worksheet.Cells[cell.RowIndex + 2, cell.ColumnIndex + 1].Value = cell.Value.ToString(); - worksheet.Cells[cell.RowIndex + 2, cell.ColumnIndex + 1].Style.Fill.PatternType = - ExcelFillStyle.Solid; - worksheet.Cells[cell.RowIndex + 2, cell.ColumnIndex + 1].Style.Fill.BackgroundColor - .SetColor(cell.Style.BackColor); - } - }); - excel.SaveAs(new FileInfo(dialog.FileName)); - } + worksheet.Cells[cell.RowIndex + 2, cell.ColumnIndex + 1].Value = cell.Value.ToString(); + worksheet.Cells[cell.RowIndex + 2, cell.ColumnIndex + 1].Style.Fill.PatternType = + ExcelFillStyle.Solid; + worksheet.Cells[cell.RowIndex + 2, cell.ColumnIndex + 1].Style.Fill.BackgroundColor + .SetColor(cell.Style.BackColor); + } + }); + excel.SaveAs(new FileInfo(dialog.FileName)); } } } \ No newline at end of file diff --git a/GradeCalc/NCalcDoubleParser.cs b/GradeCalc/NCalcDoubleParser.cs index 0c416d9..0beea7a 100644 --- a/GradeCalc/NCalcDoubleParser.cs +++ b/GradeCalc/NCalcDoubleParser.cs @@ -4,33 +4,24 @@ namespace GradeCalc { internal static class NCalcDoubleParser { - public static double Parse(object NCalcOutput) + public static double Parse(object nCalcOutput) { - if (NCalcOutput.GetType() == typeof(bool)) - return (bool) NCalcOutput ? 1 : 0; - if (NCalcOutput.GetType() == typeof(byte)) - return (byte) NCalcOutput; - if (NCalcOutput.GetType() == typeof(sbyte)) - return (sbyte) NCalcOutput; - if (NCalcOutput.GetType() == typeof(short)) - return (short) NCalcOutput; - if (NCalcOutput.GetType() == typeof(ushort)) - return (ushort) NCalcOutput; - if (NCalcOutput.GetType() == typeof(int)) - return (int) NCalcOutput; - if (NCalcOutput.GetType() == typeof(uint)) - return (uint) NCalcOutput; - if (NCalcOutput.GetType() == typeof(long)) - return (long) NCalcOutput; - if (NCalcOutput.GetType() == typeof(ulong)) - return (ulong) NCalcOutput; - if (NCalcOutput.GetType() == typeof(float)) - return (float) NCalcOutput; - if (NCalcOutput.GetType() == typeof(double)) - return (double) NCalcOutput; - if (NCalcOutput.GetType() == typeof(decimal)) - return (double) (decimal) NCalcOutput; - throw new ArgumentException("Type mismatch! (" + NCalcOutput.GetType() + ")"); + return nCalcOutput switch + { + bool n => (n ? 1 : 0), + byte n => n, + sbyte n => n, + short n => n, + ushort n => n, + int n => n, + uint n => n, + long n => n, + ulong n => n, + float n => n, + double n => n, + decimal n => (double) n, + _ => throw new ArgumentException("Type mismatch! (" + nCalcOutput.GetType() + ")") + }; } } } \ No newline at end of file diff --git a/GradeCalc/Properties/AssemblyInfo.cs b/GradeCalc/Properties/AssemblyInfo.cs index 8661c5d..4e822f0 100644 --- a/GradeCalc/Properties/AssemblyInfo.cs +++ b/GradeCalc/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ using System.Runtime.InteropServices; // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyVersion("1.0.*")] [assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/GradeCalc/app.manifest b/GradeCalc/app.manifest deleted file mode 100644 index ab36f16..0000000 --- a/GradeCalc/app.manifest +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - diff --git a/GradeCalc/packages.config b/GradeCalc/packages.config index 0351597..f5e624f 100644 --- a/GradeCalc/packages.config +++ b/GradeCalc/packages.config @@ -3,7 +3,8 @@ - + + diff --git a/PostBuild.cs b/PostBuild.cs deleted file mode 100644 index 35d4d6f..0000000 --- a/PostBuild.cs +++ /dev/null @@ -1,38 +0,0 @@ -using System; -using System.IO; -using System.IO.Compression; -using System.Linq; - -public class Program -{ - public static void Main(string[] args) - { - //Variables - string TargetDir = args[0].Trim('"').TrimEnd('\\'); - string TargetFileName = args[1].Trim('"'); - //Copy Data dir - if (File.Exists(TargetDir + ".zip")) - File.Delete(TargetDir + ".zip"); - if (File.Exists(TargetDir + @"\package.zip")) - File.Delete(TargetDir + @"\package.zip"); - if (Directory.Exists(TargetDir + @"\package")) - Directory.Delete(TargetDir + @"\package", true); - ZipFile.CreateFromDirectory(TargetDir, TargetDir + ".zip"); - Directory.CreateDirectory(TargetDir + @"\package\Data"); - ZipFile.ExtractToDirectory(TargetDir + ".zip", TargetDir + @"\package\Data"); - File.Delete(TargetDir + ".zip"); - //Remove useless Files - Directory.GetFiles(TargetDir + @"\package\Data") - .Where(s => new string[] { ".xml", ".pdb" }.Contains(Path.GetExtension(s))) - .ToList().ForEach(s => File.Delete(s)); - //Add package scripts - string programName = Path.GetFileNameWithoutExtension(TargetFileName); - File.WriteAllText(TargetDir + @"\package\Install.bat", - "@echo off\r\necho INSTALL\r\npowershell \"$s=(New-Object -COM WScript.Shell).CreateShortcut('%appdata%\\Microsoft\\Windows\\Start Menu\\Programs\\" + programName + ".lnk');$s.TargetPath='%cd%\\" + programName + ".exe';$s.Save()\"\r\ntimeout /t 1"); - File.WriteAllText(TargetDir + @"\package\Remove.bat", - "@echo off\r\necho REMOVE\r\ndel \"%appdata%\\Microsoft\\Windows\\Start Menu\\Programs\\" + programName + ".lnk\"\r\ntaskkill /f /im \"" + programName + ".exe\"\r\ntimeout /t 1"); - //Package up result - ZipFile.CreateFromDirectory(TargetDir + @"\package", TargetDir + @"\package.zip"); - Directory.Delete(TargetDir + @"\package", true); - } -}