From 3f65aa4f74a1062641bcfa36b550e743ca0cb575 Mon Sep 17 00:00:00 2001 From: Giduac Date: Thu, 26 Dec 2024 12:28:44 +0100 Subject: [PATCH] 1908-V85-KryptonDataGridViewDateTimePickerCell-updates KryptonDataGridViewDateTimePickerCell updates Change log entry will be provided when 1908 is fully completed --- .../KryptonDataGridViewDateTimePickerCell.cs | 288 ++++++++---------- ...KryptonDataGridViewDateTimePickerColumn.cs | 45 ++- 2 files changed, 152 insertions(+), 181 deletions(-) diff --git a/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewDateTimePickerCell.cs b/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewDateTimePickerCell.cs index 39e1a0d24..091f72832 100644 --- a/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewDateTimePickerCell.cs +++ b/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewDateTimePickerCell.cs @@ -5,7 +5,7 @@ * © Component Factory Pty Ltd, 2006 - 2016, (Version 4.5.0.0) All rights reserved. * * New BSD 3-Clause License (https://github.com/Krypton-Suite/Standard-Toolkit/blob/master/LICENSE) - * Modifications by Peter Wagner(aka Wagnerp) & Simon Coghlan(aka Smurf-IV), et al. 2017 - 2023. All rights reserved. + * Modifications by Peter Wagner (aka Wagnerp), Simon Coghlan (aka Smurf-IV), Giduac & Ahmed Abdelhameed et al. 2017 - 2025. All rights reserved. * */ #endregion @@ -18,12 +18,9 @@ namespace Krypton.Toolkit public class KryptonDataGridViewDateTimePickerCell : DataGridViewTextBoxCell { #region Static Fields - [ThreadStatic] - private static KryptonDateTimePicker _paintingDateTime; private static readonly DateTimeConverter _dtc = new DateTimeConverter(); private static readonly Type _defaultEditType = typeof(KryptonDataGridViewDateTimePickerEditingControl); private static readonly Type _defaultValueType = typeof(DateTime); - private static readonly Size _sizeLarge = new Size(10000, 10000); #endregion #region Instance Fields @@ -52,17 +49,6 @@ public class KryptonDataGridViewDateTimePickerCell : DataGridViewTextBoxCell /// public KryptonDataGridViewDateTimePickerCell() { - // Create a thread specific KryptonDateTimePicker control used for the painting of the non-edited cells - if (_paintingDateTime == null) - { - _paintingDateTime = new KryptonDateTimePicker - { - ShowBorder = false - }; - _paintingDateTime.StateCommon.Border.Width = 0; - _paintingDateTime.StateCommon.Border.Draw = InheritBool.False; - } - // Set the default values of the properties: _showCheckBox = false; _showUpDown = false; @@ -73,7 +59,7 @@ public KryptonDataGridViewDateTimePickerCell() _maxDate = DateTime.MaxValue; _minDate = DateTime.MinValue; _format = DateTimePickerFormat.Long; - _calendarDimensions = new Size(1,1); + _calendarDimensions = new Size(1, 1); _calendarTodayText = "Today:"; _calendarFirstDayOfWeek = Day.Default; _calendarShowToday = true; @@ -107,26 +93,25 @@ public KryptonDataGridViewDateTimePickerCell() public override object Clone() { var dateTimeCell = base.Clone() as KryptonDataGridViewDateTimePickerCell; - if (dateTimeCell != null) - { - dateTimeCell.AutoShift = AutoShift; - dateTimeCell.Checked = Checked; - dateTimeCell.ShowCheckBox = ShowCheckBox; - dateTimeCell.ShowUpDown = ShowUpDown; - dateTimeCell.CustomFormat = CustomFormat; - dateTimeCell.CustomNullText = CustomNullText; - dateTimeCell.MaxDate = MaxDate; - dateTimeCell.MinDate = MinDate; - dateTimeCell.Format = Format; - dateTimeCell.CalendarDimensions = CalendarDimensions; - dateTimeCell.CalendarTodayText = CalendarTodayText; - dateTimeCell.CalendarFirstDayOfWeek = CalendarFirstDayOfWeek; - dateTimeCell.CalendarShowToday = CalendarShowToday; - dateTimeCell.CalendarCloseOnTodayClick = CalendarCloseOnTodayClick; - dateTimeCell.CalendarShowTodayCircle = CalendarShowTodayCircle; - dateTimeCell.CalendarShowWeekNumbers = CalendarShowWeekNumbers; - dateTimeCell.CalendarTodayDate = CalendarTodayDate; - } + + dateTimeCell.AutoShift = AutoShift; + dateTimeCell.Checked = Checked; + dateTimeCell.ShowCheckBox = ShowCheckBox; + dateTimeCell.ShowUpDown = ShowUpDown; + dateTimeCell.CustomFormat = CustomFormat; + dateTimeCell.CustomNullText = CustomNullText; + dateTimeCell.MaxDate = MaxDate; + dateTimeCell.MinDate = MinDate; + dateTimeCell.Format = Format; + dateTimeCell.CalendarDimensions = CalendarDimensions; + dateTimeCell.CalendarTodayText = CalendarTodayText; + dateTimeCell.CalendarFirstDayOfWeek = CalendarFirstDayOfWeek; + dateTimeCell.CalendarShowToday = CalendarShowToday; + dateTimeCell.CalendarCloseOnTodayClick = CalendarCloseOnTodayClick; + dateTimeCell.CalendarShowTodayCircle = CalendarShowTodayCircle; + dateTimeCell.CalendarShowWeekNumbers = CalendarShowWeekNumbers; + dateTimeCell.CalendarTodayDate = CalendarTodayDate; + return dateTimeCell; } @@ -396,7 +381,7 @@ public bool CalendarCloseOnTodayClick } } - + /// /// The CalendarShowTodayCircle property replicates the one from the KryptonDateTimePicker control /// @@ -462,7 +447,7 @@ public DateTime CalendarTodayDate [EditorBrowsable(EditorBrowsableState.Advanced)] public override void DetachEditingControl() { - DataGridView dataGridView = DataGridView; + DataGridView? dataGridView = DataGridView; if (dataGridView?.EditingControl == null) { throw new InvalidOperationException("Cell is detached or its grid has no editing control."); @@ -477,12 +462,12 @@ public override void DetachEditingControl() /// set according to the cell properties. /// public override void InitializeEditingControl(int rowIndex, - object initialFormattedValue, - DataGridViewCellStyle dataGridViewCellStyle) + object? initialFormattedValue, + DataGridViewCellStyle dataGridViewCellStyle) { base.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle); - if (DataGridView.EditingControl is KryptonDateTimePicker dateTime) + if (DataGridView!.EditingControl is KryptonDateTimePicker dateTime) { if (OwningColumn is KryptonDataGridViewDateTimePickerColumn dateTimeColumn) { @@ -514,8 +499,7 @@ public override void InitializeEditingControl(int rowIndex, } else { - var dt = (DateTime)_dtc.ConvertFromInvariantString(initialFormattedValueStr); - if (dt != null) + if (_dtc.ConvertFromInvariantString(initialFormattedValueStr) is DateTime dt) { dateTime.Value = dt; } @@ -537,23 +521,21 @@ public override void InitializeEditingControl(int rowIndex, /// A TypeConverter associated with the formatted value type that provides custom conversion from the value type, or null if no such custom conversion is needed. /// A bitwise combination of DataGridViewDataErrorContexts values describing the context in which the formatted value is needed. /// - protected override object GetFormattedValue(object value, int rowIndex, - ref DataGridViewCellStyle cellStyle, - TypeConverter valueTypeConverter, - TypeConverter formattedValueTypeConverter, - DataGridViewDataErrorContexts context) + protected override object? GetFormattedValue(object? value, + int rowIndex, + ref DataGridViewCellStyle cellStyle, + TypeConverter? valueTypeConverter, + TypeConverter? formattedValueTypeConverter, + DataGridViewDataErrorContexts context) { if ((value == null) || (value == DBNull.Value)) { return string.Empty; } - else + + if (value is DateTime dt) { - var dt = (DateTime)value; - if (dt != null) - { - return _dtc.ConvertToInvariantString(dt); - } + return _dtc.ConvertToInvariantString(dt); } return base.GetFormattedValue(value, rowIndex, ref cellStyle, valueTypeConverter, formattedValueTypeConverter, context); @@ -567,10 +549,10 @@ protected override object GetFormattedValue(object value, int rowIndex, /// A TypeConverter for the display value type, or null to use the default converter. /// A TypeConverter for the cell value type, or null to use the default converter. /// - public override object ParseFormattedValue(object formattedValue, - DataGridViewCellStyle cellStyle, - TypeConverter formattedValueTypeConverter, - TypeConverter valueTypeConverter) + public override object ParseFormattedValue(object? formattedValue, + DataGridViewCellStyle cellStyle, + TypeConverter? formattedValueTypeConverter, + TypeConverter? valueTypeConverter) { if (formattedValue == null) { @@ -578,36 +560,78 @@ public override object ParseFormattedValue(object formattedValue, } else { - var stringValue = (string)formattedValue; - return string.IsNullOrEmpty(stringValue) ? DBNull.Value : _dtc.ConvertFromInvariantString(stringValue); + string stringValue = (string)formattedValue; + return string.IsNullOrEmpty(stringValue) ? DBNull.Value : _dtc.ConvertFromInvariantString(stringValue)!; } } - - /// - /// 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); - } #endregion #region Protected + /// + 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 is not null + && KryptonOwningColumn?.CellIndicatorImage is Image image) + { + int pos; + Rectangle textArea; + var righToLeft = DataGridView.RightToLeft == RightToLeft.Yes; + + if (righToLeft) + { + pos = cellBounds.Left; + + // The WinForms cell content always receives padding of one by default, custom padding is added tot that. + textArea = new Rectangle( + 1 + cellBounds.Left + cellStyle.Padding.Left + image.Width, + 1 + cellBounds.Top + cellStyle.Padding.Top, + cellBounds.Width - cellStyle.Padding.Left - cellStyle.Padding.Right - image.Width - 3, + cellBounds.Height - cellStyle.Padding.Top - cellStyle.Padding.Bottom - 2); + } + else + { + pos = cellBounds.Right - image.Width; + + // The WinForms cell content always receives padding of one by default, custom padding is added tot that. + textArea = new Rectangle( + 1 + cellBounds.Left + cellStyle.Padding.Left, + 1 + cellBounds.Top + cellStyle.Padding.Top, + cellBounds.Width - cellStyle.Padding.Left - cellStyle.Padding.Right - image.Width - 3, + cellBounds.Height - cellStyle.Padding.Top - cellStyle.Padding.Bottom - 2); + } + + // When the Krypton column is part of a WinForms DataGridView let the default paint routine paint the cell. + // Afterwards we paint the text and drop down image. + if (DataGridView is DataGridView) + { + base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, null, string.Empty, errorText, cellStyle, advancedBorderStyle, paintParts); + } + + // Draw the drop down button, only if no ErrorText has been set. + // If the ErrorText is set, only the error icon is shown. Otherwise both are painted on the same spot. + if (ErrorText.Length == 0) + { + graphics.DrawImage(image, new Point(pos, textArea.Top)); + + if (DataGridView.Rows.SharedRow(rowIndex).Index != -1 + && formattedValue is string str + && str.Length > 0 + && DateTime.TryParse(str, out DateTime dt)) + { + formattedValue = dt.ToString(InheritedStyle.Format); + } + } + else + { + formattedValue = errorText; + } + + TextRenderer.DrawText(graphics, formattedValue?.ToString() ?? string.Empty, cellStyle.Font, textArea, cellStyle.ForeColor, + KryptonDataGridViewUtilities.ComputeTextFormatFlagsForCellStyleAlignment(righToLeft, cellStyle.Alignment, cellStyle.WrapMode)); + } + } + /// /// 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. @@ -617,14 +641,10 @@ protected override Rectangle GetErrorIconBounds(Graphics graphics, DataGridViewC 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; - } + + errorIconBounds.X = DataGridView!.RightToLeft == RightToLeft.Yes + ? errorIconBounds.Left + ButtonsWidth + : errorIconBounds.Left - ButtonsWidth; return errorIconBounds; } @@ -649,86 +669,12 @@ protected override Size GetPreferredSize(Graphics graphics, DataGridViewCellStyl return preferredSize; } - - /// - /// 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 KryptonDateTimePicker 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 KryptonDateTimePicker 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; - } - - _paintingDateTime.RightToLeft = DataGridView.RightToLeft; - _paintingDateTime.Format = Format; - _paintingDateTime.CustomFormat = CustomFormat; - _paintingDateTime.CustomNullText = CustomNullText; - _paintingDateTime.MaxDate = MaxDate; - _paintingDateTime.MinDate = MinDate; - - var drawText = CustomNullText; - if ((value == null) || (value == DBNull.Value)) - { - _paintingDateTime.ValueNullable = value; - _paintingDateTime.PerformLayout(); - } - else - { - _paintingDateTime.Value = (DateTime)value; - _paintingDateTime.PerformLayout(); - drawText = _paintingDateTime.Text; - } - - base.Paint(graphics, clipBounds, cellBounds, rowIndex, - cellState, value, drawText, errorText, - cellStyle, advancedBorderStyle, paintParts); - } #endregion #region Private - private KryptonDataGridViewDateTimePickerEditingControl EditingDateTimePicker => - DataGridView.EditingControl as KryptonDataGridViewDateTimePickerEditingControl; - - private Rectangle GetAdjustedEditingControlBounds(Rectangle editingControlBounds, - DataGridViewCellStyle cellStyle) - { - // Adjust the vertical location of the editing control: - var preferredHeight = _paintingDateTime.GetPreferredSize(_sizeLarge).Height + 2; - 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; - } + private KryptonDataGridViewDateTimePickerEditingControl EditingDateTimePicker => + DataGridView!.EditingControl as KryptonDataGridViewDateTimePickerEditingControl; private void OnCommonChange() { @@ -746,10 +692,9 @@ private void OnCommonChange() } private bool OwnsEditingDateTimePicker(int rowIndex) => - rowIndex != -1 && DataGridView is { EditingControl: KryptonDataGridViewDateTimePickerEditingControl control } + rowIndex != -1 && DataGridView is { EditingControl: KryptonDataGridViewDateTimePickerEditingControl control } && (rowIndex == ((IDataGridViewEditingControl)control).EditingControlRowIndex); - private static bool PartPainted(DataGridViewPaintParts paintParts, DataGridViewPaintParts paintPart) => (paintParts & paintPart) != 0; #endregion #region Internal @@ -905,6 +850,11 @@ internal void SetCalendarTodayDate(int rowIndex, DateTime value) EditingDateTimePicker.CalendarTodayDate = value; } } + + /// + /// Type casted version of OwningColumn + /// + internal KryptonDataGridViewDateTimePickerColumn? KryptonOwningColumn => OwningColumn as KryptonDataGridViewDateTimePickerColumn; #endregion } } \ No newline at end of file diff --git a/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewDateTimePickerColumn.cs b/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewDateTimePickerColumn.cs index c8f7b7f85..21bc190d8 100644 --- a/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewDateTimePickerColumn.cs +++ b/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewDateTimePickerColumn.cs @@ -5,7 +5,7 @@ * © Component Factory Pty Ltd, 2006 - 2016, (Version 4.5.0.0) All rights reserved. * * New BSD 3-Clause License (https://github.com/Krypton-Suite/Standard-Toolkit/blob/master/LICENSE) - * Modifications by Peter Wagner(aka Wagnerp) & Simon Coghlan(aka Smurf-IV), et al. 2017 - 2023. All rights reserved. + * Modifications by Peter Wagner (aka Wagnerp), Simon Coghlan (aka Smurf-IV), Giduac & Ahmed Abdelhameed et al. 2017 - 2025. All rights reserved. * */ #endregion @@ -20,11 +20,12 @@ namespace Krypton.Toolkit public class KryptonDataGridViewDateTimePickerColumn : KryptonDataGridViewIconColumn { #region Instance Fields - private readonly DateTimeList _annualDates; private readonly DateTimeList _monthlyDates; private readonly DateTimeList _dates; - #endregion + // Cell indicator image instance + private readonly KryptonDataGridViewCellIndicatorImage _kryptonDataGridViewCellIndicatorImage; + #endregion #region Identity /// @@ -33,9 +34,10 @@ public class KryptonDataGridViewDateTimePickerColumn : KryptonDataGridViewIconCo public KryptonDataGridViewDateTimePickerColumn() : base(new KryptonDataGridViewDateTimePickerCell()) { - _annualDates = new DateTimeList(); - _monthlyDates = new DateTimeList(); - _dates = new DateTimeList(); + _annualDates = []; + _monthlyDates = []; + _dates = []; + _kryptonDataGridViewCellIndicatorImage = new(); } /// @@ -62,6 +64,7 @@ public override object Clone() { var cloned = base.Clone() as KryptonDataGridViewDateTimePickerColumn; + cloned.CalendarAnnuallyBoldedDates = CalendarAnnuallyBoldedDates; cloned.CalendarMonthlyBoldedDates = CalendarMonthlyBoldedDates; cloned.CalendarBoldedDates = CalendarBoldedDates; @@ -76,7 +79,7 @@ public override object Clone() /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public override DataGridViewCell CellTemplate + public override DataGridViewCell? CellTemplate { get => base.CellTemplate; @@ -808,7 +811,8 @@ public DateTime CalendarTodayDate [Category(@"MonthCalendar")] [Description(@"Indicates which annual dates should be boldface.")] [Localizable(true)] - public DateTime[] CalendarAnnuallyBoldedDates + [AllowNull] + public DateTime[]? CalendarAnnuallyBoldedDates { get => _annualDates.ToArray(); @@ -835,7 +839,8 @@ public DateTime[] CalendarAnnuallyBoldedDates [Category(@"MonthCalendar")] [Description(@"Indicates which monthly dates should be boldface.")] [Localizable(true)] - public DateTime[] CalendarMonthlyBoldedDates + [AllowNull] + public DateTime[]? CalendarMonthlyBoldedDates { get => _monthlyDates.ToArray(); @@ -862,7 +867,8 @@ public DateTime[] CalendarMonthlyBoldedDates [Category(@"MonthCalendar")] [Description(@"Indicates which dates should be boldface.")] [Localizable(true)] - public DateTime[] CalendarBoldedDates + [AllowNull] + public DateTime[]? CalendarBoldedDates { get => _dates.ToArray(); @@ -889,9 +895,24 @@ public DateTime[] CalendarBoldedDates /// /// Small utility function that returns the template cell as a KryptonDataGridViewDateTimePickerCell /// - private KryptonDataGridViewDateTimePickerCell? DateTimePickerCellTemplate => (KryptonDataGridViewDateTimePickerCell)CellTemplate; - + private KryptonDataGridViewDateTimePickerCell? DateTimePickerCellTemplate => CellTemplate as KryptonDataGridViewDateTimePickerCell; #endregion + #region Internal + /// + /// Provides the cell indicator images to the cells from from this column instance.
+ /// For internal use only. + ///
+ internal Image? CellIndicatorImage => _kryptonDataGridViewCellIndicatorImage.Image; + #endregion Internal + + #region Protected + /// + protected override void OnDataGridViewChanged() + { + _kryptonDataGridViewCellIndicatorImage.DataGridView = DataGridView as KryptonDataGridView; + base.OnDataGridViewChanged(); + } + #endregion Protected } } \ No newline at end of file