This commit is contained in:
CreepyCrafter24 2020-03-11 21:50:16 +01:00
parent 8a44670977
commit 37533290c9
11 changed files with 173 additions and 1623 deletions

View File

@ -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
/// <summary>
/// Constructor for the DataGridViewNumericUpDownCell cell type
/// </summary>
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;
}
/// <summary>
/// The DecimalPlaces property replicates the one from the NumericUpDown control
/// </summary>
[
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
}
}
}
/// <summary>
/// Returns the current DataGridView EditingControl as a DataGridViewNumericUpDownEditingControl control
/// </summary>
private DataGridViewNumericUpDownEditingControl EditingNumericUpDown =>
DataGridView.EditingControl as DataGridViewNumericUpDownEditingControl;
/// <summary>
/// Define the type of the cell's editing control
/// </summary>
public override Type EditType => defaultEditType; // the type is DataGridViewNumericUpDownEditingControl
/// <summary>
/// The Increment property replicates the one from the NumericUpDown control
/// </summary>
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.
}
}
/// <summary>
/// The Maximum property replicates the one from the NumericUpDown control
/// </summary>
public decimal Maximum
{
get => maximum;
set
{
if (maximum != value)
{
SetMaximum(RowIndex, value);
OnCommonChange();
}
}
}
/// <summary>
/// The Minimum property replicates the one from the NumericUpDown control
/// </summary>
public decimal Minimum
{
get => minimum;
set
{
if (minimum != value)
{
SetMinimum(RowIndex, value);
OnCommonChange();
}
}
}
/// <summary>
/// The ThousandsSeparator property replicates the one from the NumericUpDown control
/// </summary>
[
DefaultValue(DATAGRIDVIEWNUMERICUPDOWNCELL_defaultThousandsSeparator)
]
public bool ThousandsSeparator
{
get => thousandsSeparator;
set
{
if (thousandsSeparator != value)
{
SetThousandsSeparator(RowIndex, value);
OnCommonChange();
}
}
}
/// <summary>
/// Returns the type of the cell's Value property
/// </summary>
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);
/// <summary>
/// Clones a DataGridViewNumericUpDownCell cell, copies all the custom properties.
/// </summary>
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;
}
/// <summary>
/// Returns the provided value constrained to be within the min and max.
/// </summary>
private decimal Constrain(decimal value)
{
Debug.Assert(minimum <= maximum);
if (value < minimum) value = minimum;
if (value > maximum) value = maximum;
return value;
}
/// <summary>
/// DetachEditingControl gets called by the DataGridView control when the editing session is ending
/// </summary>
[
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();
}
/// <summary>
/// Adjusts the location and size of the editing control given the alignment characteristics of the cell
/// </summary>
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;
}
/// <summary>
/// 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.
/// </summary>
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;
}
/// <summary>
/// Customized implementation of the GetFormattedValue function in order to include the decimal and thousand separator
/// characters in the formatted representation of the cell value.
/// </summary>
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;
}
/// <summary>
/// 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.
/// </summary>
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;
}
/// <summary>
/// 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.
/// </summary>
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;
}
}
/// <summary>
/// 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.
/// </summary>
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;
}
/// <summary>
/// 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.
/// </summary>
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);
}
}
/// <summary>
/// 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.
/// </summary>
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;
}
/// <summary>
/// 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).
/// </summary>
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);
}
}
/// <summary>
/// Little utility function called by the Paint function to see if a particular part needs to be painted.
/// </summary>
private static bool PartPainted(DataGridViewPaintParts paintParts, DataGridViewPaintParts paintPart) =>
(paintParts & paintPart) != 0;
/// <summary>
/// Custom implementation of the PositionEditingControl method called by the DataGridView control when it
/// needs to relocate and/or resize the editing control.
/// </summary>
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);
}
/// <summary>
/// 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.
/// </summary>
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;
}
/// <summary>
/// Returns a standard textual representation of the cell.
/// </summary>
public override string ToString() => "DataGridViewNumericUpDownCell { ColumnIndex=" +
ColumnIndex.ToString(CultureInfo.CurrentCulture) + ", RowIndex=" +
RowIndex.ToString(CultureInfo.CurrentCulture) + " }";
/// <summary>
/// Little utility function used by both the cell and column types to translate a DataGridViewContentAlignment value
/// into
/// a HorizontalAlignment value.
/// </summary>
internal static HorizontalAlignment TranslateAlignment(DataGridViewContentAlignment align)
{
if ((align & anyRight) != 0)
return HorizontalAlignment.Right;
if ((align & anyCenter) != 0)
return HorizontalAlignment.Center;
return HorizontalAlignment.Left;
}
}
}

View File

@ -1,270 +0,0 @@
using System;
using System.ComponentModel;
using System.Globalization;
using System.Text;
using System.Windows.Forms;
namespace GradeCalc
{
/// <summary>
/// Custom column type dedicated to the DataGridViewNumericUpDownCell cell type.
/// </summary>
public class DataGridViewNumericUpDownColumn : DataGridViewColumn
{
/// <summary>
/// Constructor for the DataGridViewNumericUpDownColumn class.
/// </summary>
public DataGridViewNumericUpDownColumn() : base(new DataGridViewNumericUpDownCell())
{
}
/// <summary>
/// Represents the implicit cell that gets cloned when adding rows to the grid.
/// </summary>
[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;
}
}
/// <summary>
/// Replicates the DecimalPlaces property of the DataGridViewNumericUpDownCell cell type.
/// </summary>
[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.
}
}
}
/// <summary>
/// Replicates the Increment property of the DataGridViewNumericUpDownCell cell type.
/// </summary>
[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);
}
}
}
}
/// <summary>
/// Replicates the Maximum property of the DataGridViewNumericUpDownCell cell type.
/// </summary>
[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.
}
}
}
/// <summary>
/// Replicates the Minimum property of the DataGridViewNumericUpDownCell cell type.
/// </summary>
[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.
}
}
}
/// <summary>
/// Replicates the ThousandsSeparator property of the DataGridViewNumericUpDownCell cell type.
/// </summary>
[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.
}
}
}
/// <summary>
/// Small utility function that returns the template cell as a DataGridViewNumericUpDownCell
/// </summary>
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);
/// <summary>
/// Returns a standard compact string representation of the column.
/// </summary>
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();
}
}
}

View File

@ -1,285 +0,0 @@
using System;
using System.Drawing;
using System.Globalization;
using System.Runtime.InteropServices;
using System.Windows.Forms;
namespace GradeCalc
{
/// <summary>
/// Defines the editing control for the DataGridViewNumericUpDownCell custom cell type.
/// </summary>
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;
/// <summary>
/// Constructor of the editing control class
/// </summary>
// The editing control must not be part of the tabbing loop
public DataGridViewNumericUpDownEditingControl() => TabStop = false;
// Beginning of the IDataGridViewEditingControl interface implementation
/// <summary>
/// Property which caches the grid that uses this editing control
/// </summary>
public virtual DataGridView EditingControlDataGridView
{
get => dataGridView;
set => dataGridView = value;
}
/// <summary>
/// Property which represents the current formatted value of the editing control
/// </summary>
public virtual object EditingControlFormattedValue
{
get => GetEditingControlFormattedValue(DataGridViewDataErrorContexts.Formatting);
set => Text = (string) value;
}
/// <summary>
/// Property which represents the row in which the editing control resides
/// </summary>
public virtual int EditingControlRowIndex { get; set; }
/// <summary>
/// Property which indicates whether the value of the editing control has changed or not
/// </summary>
public virtual bool EditingControlValueChanged
{
get => valueChanged;
set => valueChanged = value;
}
/// <summary>
/// Property which determines which cursor must be used for the editing panel,
/// i.e. the parent of the editing control.
/// </summary>
public virtual Cursor EditingPanelCursor => Cursors.Default;
/// <summary>
/// Property which indicates whether the editing control needs to be repositioned
/// when its value changes.
/// </summary>
public virtual bool RepositionEditingControlOnValueChange => false;
/// <summary>
/// Method called by the grid before the editing control is shown so it can adapt to the
/// provided cell style.
/// </summary>
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);
}
/// <summary>
/// Method called by the grid on keystrokes to determine if the editing control is
/// interested in the key or not.
/// </summary>
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;
}
/// <summary>
/// Returns the current value of the editing control.
/// </summary>
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;
}
}
/// <summary>
/// Called by the grid to give the editing control a chance to prepare itself for
/// the editing session.
/// </summary>
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
/// <summary>
/// Small utility function that updates the local dirty state and
/// notifies the grid of the value change.
/// </summary>
private void NotifyDataGridViewOfValueChange()
{
if (!valueChanged)
{
valueChanged = true;
dataGridView.NotifyCurrentCellDirty(true);
}
}
/// <summary>
/// Listen to the KeyPress notification to know when the value changed, and
/// notify the grid of the change.
/// </summary>
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();
}
/// <summary>
/// Listen to the ValueChanged notification to forward the change to the grid.
/// </summary>
protected override void OnValueChanged(EventArgs e)
{
base.OnValueChanged(e);
if (Focused)
// Let the DataGridView know about the value change
NotifyDataGridViewOfValueChange();
}
/// <summary>
/// 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.
/// </summary>
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);
}
}
}

View File

@ -1,155 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Antlr4.CodeGenerator.4.6.6\build\Antlr4.CodeGenerator.props" Condition="Exists('..\packages\Antlr4.CodeGenerator.4.6.6\build\Antlr4.CodeGenerator.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<Project Sdk="Microsoft.NET.Sdk.WindowsDesktop">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{D5948BBB-1F03-497A-A2BA-DD1E6F54A2A8}</ProjectGuid>
<TargetFramework>netcoreapp3.1</TargetFramework>
<OutputType>WinExe</OutputType>
<RootNamespace>GradeCalc</RootNamespace>
<AssemblyName>GradeCalc</AssemblyName>
<TargetFrameworkVersion>v4.6.1</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
<Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
<TargetFrameworkProfile />
<PublishUrl>publish\</PublishUrl>
<Install>true</Install>
<InstallFrom>Disk</InstallFrom>
<UpdateEnabled>false</UpdateEnabled>
<UpdateMode>Foreground</UpdateMode>
<UpdateInterval>7</UpdateInterval>
<UpdateIntervalUnits>Days</UpdateIntervalUnits>
<UpdatePeriodically>false</UpdatePeriodically>
<UpdateRequired>false</UpdateRequired>
<MapFileExtensions>true</MapFileExtensions>
<ApplicationRevision>0</ApplicationRevision>
<ApplicationVersion>1.0.0.%2a</ApplicationVersion>
<IsWebBootstrapper>false</IsWebBootstrapper>
<UseApplicationTrust>false</UseApplicationTrust>
<BootstrapperEnabled>true</BootstrapperEnabled>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<PlatformTarget>AnyCPU</PlatformTarget>
<DebugType>none</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<UseWindowsForms>true</UseWindowsForms>
<Deterministic>false</Deterministic>
</PropertyGroup>
<PropertyGroup>
<ApplicationManifest>app.manifest</ApplicationManifest>
<PostBuildEvent>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</PostBuildEvent>
</PropertyGroup>
<ItemGroup>
<Reference Include="Antlr4.Runtime, Version=4.6.0.0, Culture=neutral, PublicKeyToken=09abb75b9ed49849, processorArchitecture=MSIL">
<HintPath>..\packages\Antlr4.Runtime.4.6.6\lib\net45\Antlr4.Runtime.dll</HintPath>
</Reference>
<Reference Include="EPPlus, Version=4.5.3.3, Culture=neutral, PublicKeyToken=ea159fdaa78159a1">
<HintPath>..\packages\EPPlus.4.5.3.3\lib\net40\EPPlus.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NCalc2, Version=1.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\NCalc2.2.1.0\lib\net46\NCalc2.dll</HintPath>
</Reference>
<Reference Include="PresentationCore" />
<Reference Include="System" />
<Reference Include="System.configuration" />
<Reference Include="System.Core" />
<Reference Include="System.Security" />
<Reference Include="System.Xml.Linq" />
<Reference Include="System.Data.DataSetExtensions" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Data" />
<Reference Include="System.Deployment" />
<Reference Include="System.Drawing" />
<Reference Include="System.Net.Http" />
<Reference Include="System.Windows.Forms" />
<Reference Include="System.Xml" />
<PackageReference Include="Antlr4" Version="4.6.6" />
<PackageReference Include="Antlr4.CodeGenerator" Version="4.6.6" />
<PackageReference Include="Antlr4.Runtime" Version="4.6.6" />
<PackageReference Include="CC-Functions.Misc" Version="1.0.6" />
<PackageReference Include="EPPlus" Version="5.0.4" />
<PackageReference Include="NCalc2" Version="2.1.0" />
</ItemGroup>
<ItemGroup>
<Compile Include="DataGridViewNumericUpDownCell.cs" />
<Compile Include="DataGridViewNumericUpDownColumn.cs" />
<Compile Include="DataGridViewNumericUpDownEditingControl.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="MainForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Include="MainForm.Designer.cs">
<DependentUpon>MainForm.cs</DependentUpon>
</Compile>
<Compile Include="NCalcDoubleParser.cs" />
<Compile Include="Program.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<EmbeddedResource Include="MainForm.resx">
<DependentUpon>MainForm.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Include="Properties\Resources.resx">
<Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput>
<SubType>Designer</SubType>
</EmbeddedResource>
<Compile Include="Properties\Resources.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Resources.resx</DependentUpon>
<DesignTime>True</DesignTime>
</Compile>
<None Include="app.manifest" />
<None Include="packages.config" />
<None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile>
</ItemGroup>
<ItemGroup>
<None Include="App.config" />
</ItemGroup>
<ItemGroup>
<BootstrapperPackage Include=".NETFramework,Version=v4.6.1">
<Visible>False</Visible>
<ProductName>Microsoft .NET Framework 4.6.1 %28x86 and x64%29</ProductName>
<Install>true</Install>
</BootstrapperPackage>
<BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
<Visible>False</Visible>
<ProductName>.NET Framework 3.5 SP1</ProductName>
<Install>false</Install>
</BootstrapperPackage>
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PostBuildEvent>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
)</PostBuildEvent>
</PropertyGroup>
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>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}.</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Antlr4.CodeGenerator.4.6.6\build\Antlr4.CodeGenerator.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Antlr4.CodeGenerator.4.6.6\build\Antlr4.CodeGenerator.props'))" />
<Error Condition="!Exists('..\packages\Antlr4.CodeGenerator.4.6.6\build\Antlr4.CodeGenerator.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Antlr4.CodeGenerator.4.6.6\build\Antlr4.CodeGenerator.targets'))" />
</Target>
<Import Project="..\packages\Antlr4.CodeGenerator.4.6.6\build\Antlr4.CodeGenerator.targets" Condition="Exists('..\packages\Antlr4.CodeGenerator.4.6.6\build\Antlr4.CodeGenerator.targets')" />
</Project>

View File

@ -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

View File

@ -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<DataGridViewNumericUpDownColumn>
taskColumns = new List<DataGridViewNumericUpDownColumn>();
_taskColumns = new List<DataGridViewNumericUpDownColumn>();
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<string[]> headerRow = new List<string[]>
{
dataGridView.Columns.OfType<DataGridViewColumn>().Select(s => s.HeaderText).ToArray()
};
string headerRange = "A1:" + char.ConvertFromUtf32(headerRow[0].Length + 64) + "1";
worksheet.Cells[headerRange].LoadFromArrays(headerRow);
dataGridView.Rows.OfType<DataGridViewRow>()
.Reverse().Skip(1).Reverse().ToList().ForEach(s =>
{
ExcelWorksheet worksheet = excel.Workbook.Worksheets.Add("Worksheet1");
List<string[]> headerRow = new List<string[]>
foreach (DataGridViewCell cell in s.Cells)
{
dataGridView.Columns.OfType<DataGridViewColumn>().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<DataGridViewRow>()
.Reverse().Skip(1).Reverse()
.Select(s => s.Cells.OfType<DataGridViewCell>()
.Select(t => t.Value.ToString())
.ToArray()
));*/
dataGridView.Rows.OfType<DataGridViewRow>()
.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));
}
}
}

View File

@ -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() + ")")
};
}
}
}

View File

@ -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")]

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<assemblyIdentity version="1.0.0.0" name="MyApplication.app"/>
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
<security>
<requestedPrivileges xmlns="urn:schemas-microsoft-com:asm.v3">
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
</requestedPrivileges>
</security>
</trustInfo>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

View File

@ -3,7 +3,8 @@
<package id="Antlr4" version="4.6.6" targetFramework="net461" developmentDependency="true" />
<package id="Antlr4.CodeGenerator" version="4.6.6" targetFramework="net461" developmentDependency="true" />
<package id="Antlr4.Runtime" version="4.6.6" targetFramework="net461" />
<package id="EPPlus" version="4.5.3.3" targetFramework="net461" />
<package id="CC-Functions.Misc" version="1.0.6" targetFramework="net461" />
<package id="EPPlus" version="5.0.4" targetFramework="net461" />
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net461" />
<package id="NCalc2" version="2.1.0" targetFramework="net48" />
<package id="System.Dynamic.Runtime" version="4.3.0" targetFramework="net48" />

View File

@ -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);
}
}