From fa45a0f8d58fb85077dba70d8b7f4aa3a337352d Mon Sep 17 00:00:00 2001 From: Giduac Date: Thu, 26 Dec 2024 11:54:13 +0100 Subject: [PATCH] 1908-V95-KDGV-ComboBoxColumn-updates KryptonDataGridViewComboBoxColumn updates Change log entry will be provided when 1908 is fully completed --- .../KryptonDataGridViewComboBoxCell.cs | 317 ++++++++++++------ .../KryptonDataGridViewComboBoxColumn.cs | 71 ++-- 2 files changed, 270 insertions(+), 118 deletions(-) diff --git a/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewComboBoxCell.cs b/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewComboBoxCell.cs index d498dd63f..2f8731941 100644 --- a/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewComboBoxCell.cs +++ b/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewComboBoxCell.cs @@ -5,13 +5,15 @@ * © 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), Giduac & Ahmed Abdelhameed et al. 2017 - 2024. 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 // ReSharper disable MemberCanBeInternal +using System.ComponentModel; + namespace Krypton.Toolkit { /// @@ -20,11 +22,8 @@ namespace Krypton.Toolkit public class KryptonDataGridViewComboBoxCell : DataGridViewTextBoxCell { #region Static Fields - [ThreadStatic] - private static KryptonComboBox? _paintingComboBox; private static readonly Type _defaultEditType = typeof(KryptonDataGridViewComboBoxEditingControl); private static readonly Type _defaultValueType = typeof(string); - private static readonly Size _sizeLarge = new Size(10000, 10000); #endregion #region Instance Fields @@ -37,7 +36,9 @@ public class KryptonDataGridViewComboBoxCell : DataGridViewTextBoxCell private string _displayMember; private string _valueMember; private object? _dataSource; - + private List _items; + private string _selectedItemText; + private bool _initialSelectedTextSet; #endregion #region Identity @@ -46,14 +47,9 @@ public class KryptonDataGridViewComboBoxCell : DataGridViewTextBoxCell /// public KryptonDataGridViewComboBoxCell() { - // Create a thread specific KryptonComboBox control used for the painting of the non-edited cells - if (_paintingComboBox == null) - { - _paintingComboBox = new KryptonComboBox(); - _paintingComboBox.SetLayoutDisplayPadding(new Padding(0, 1, 1, 0)); - _paintingComboBox.StateCommon.ComboBox.Border.Width = 0; - _paintingComboBox.StateCommon.ComboBox.Border.Draw = InheritBool.False; - } + _items = []; + _selectedItemText = string.Empty; + _initialSelectedTextSet = false; _dropDownStyle = ComboBoxStyle.DropDown; _maxDropDownItems = 8; @@ -86,7 +82,7 @@ public override string ToString() => /// Gets the items in the combobox. /// The items. - public ComboBox.ObjectCollection Items => _paintingComboBox!.ComboBox.Items; + public List Items => _items; /// /// Clones a DataGridViewComboBoxCell cell, copies all the custom properties. @@ -111,8 +107,7 @@ public override object Clone() /// The DropDownStyle property replicates the one from the KryptonComboBox control /// [DefaultValue(0)] - public ComboBoxStyle DropDownStyle - { + public ComboBoxStyle DropDownStyle { get => _dropDownStyle; set @@ -134,8 +129,7 @@ public ComboBoxStyle DropDownStyle /// The MaxDropDownItems property replicates the one from the KryptonComboBox control /// [DefaultValue(8)] - public int MaxDropDownItems - { + public int MaxDropDownItems { get => _maxDropDownItems; set @@ -152,8 +146,7 @@ public int MaxDropDownItems /// The DropDownHeight property replicates the one from the KryptonComboBox control /// [DefaultValue(200)] - public int DropDownHeight - { + public int DropDownHeight { get => _dropDownHeight; set @@ -170,8 +163,7 @@ public int DropDownHeight /// The DropDownWidth property replicates the one from the KryptonComboBox control /// [DefaultValue(121)] - public int DropDownWidth - { + public int DropDownWidth { get => _dropDownWidth; set @@ -188,8 +180,7 @@ public int DropDownWidth /// The AutoCompleteMode property replicates the one from the KryptonComboBox control /// [DefaultValue(AutoCompleteMode.None)] - public AutoCompleteMode AutoCompleteMode - { + public AutoCompleteMode AutoCompleteMode { get => _autoCompleteMode; set @@ -206,8 +197,7 @@ public AutoCompleteMode AutoCompleteMode /// The AutoCompleteSource property replicates the one from the KryptonComboBox control /// [DefaultValue(AutoCompleteSource.None)] - public AutoCompleteSource AutoCompleteSource - { + public AutoCompleteSource AutoCompleteSource { get => _autoCompleteSource; set @@ -224,8 +214,7 @@ public AutoCompleteSource AutoCompleteSource /// The DisplayMember property replicates the one from the KryptonComboBox control /// [DefaultValue(@"")] - public string DisplayMember - { + public string DisplayMember { get => _displayMember; set @@ -242,8 +231,7 @@ public string DisplayMember /// The ValueMember property replicates the one from the KryptonComboBox control /// [DefaultValue(@"")] - public string ValueMember - { + public string ValueMember { get => _valueMember; set @@ -264,8 +252,7 @@ public string ValueMember [AttributeProvider(typeof(IListSource))] [RefreshProperties(RefreshProperties.Repaint)] [DefaultValue(null)] - public object? DataSource - { + public object? DataSource { get => _dataSource; set { @@ -292,8 +279,14 @@ public override void DetachEditingControl() if (dataGridView.EditingControl is KryptonComboBox comboBox) { + _selectedItemText = comboBox.Text; comboBox.DataSource = null; } + else + { + _selectedItemText = string.Empty; + } + base.DetachEditingControl(); } @@ -304,30 +297,28 @@ 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 KryptonComboBox comboBox) { - var comboColumn = OwningColumn as KryptonDataGridViewComboBoxColumn; - - if (comboColumn is not null && comboColumn.DataSource is null) + if (KryptonOwningColumn is not null && KryptonOwningColumn.DataSource is null) { - var strings = new object[comboColumn.Items.Count]; + var strings = new object[KryptonOwningColumn.Items.Count]; for (var i = 0; i < strings.Length; i++) { - strings[i] = comboColumn.Items[i]; + strings[i] = KryptonOwningColumn.Items[i]; } comboBox.Items.Clear(); comboBox.Items.AddRange(strings); - var autoAppend = new string[comboColumn.AutoCompleteCustomSource.Count]; + var autoAppend = new string[KryptonOwningColumn.AutoCompleteCustomSource.Count]; for (var j = 0; j < autoAppend.Length; j++) { - autoAppend[j] = comboColumn.AutoCompleteCustomSource[j]; + autoAppend[j] = KryptonOwningColumn.AutoCompleteCustomSource[j]; } comboBox.AutoCompleteCustomSource.Clear(); @@ -342,38 +333,89 @@ public override void InitializeEditingControl(int rowIndex, comboBox.AutoCompleteMode = AutoCompleteMode; comboBox.DisplayMember = DisplayMember; comboBox.ValueMember = ValueMember; - comboBox.DataSource = comboColumn?.DataSource; + comboBox.DataSource = KryptonOwningColumn?.DataSource; + + // Restore the state, if needed. + if (!(Value is DBNull || Value is null)) + { + if (KryptonOwningColumn is not null + && KryptonOwningColumn.DataSource is not null + && ValueMember.Length > 0) + { + comboBox.SelectedValue = Value; + } + else if (comboBox.Items.Count > 0) + { + comboBox.SelectedIndex = comboBox.Items.IndexOf(Value.ToString()); + } + } - comboBox.Text = initialFormattedValue as string ?? string.Empty; + _selectedItemText = comboBox.Text; } } + #endregion - /// - /// 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) + #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) { - Rectangle editingControlBounds = PositionEditingPanel(cellBounds, cellClip, cellStyle, - singleVerticalBorderAdded, singleHorizontalBorderAdded, - isFirstDisplayedColumn, isFirstDisplayedRow); + if (!_initialSelectedTextSet) + { + _initialSelectedTextSet = SetInitialSelectedItemText(rowIndex); + }; - editingControlBounds = GetAdjustedEditingControlBounds(editingControlBounds, cellStyle); - DataGridView!.EditingControl!.Location = new Point(editingControlBounds.X, editingControlBounds.Y); - DataGridView.EditingControl.Size = new Size(editingControlBounds.Width, editingControlBounds.Height); - } + if (DataGridView is not null + && KryptonOwningColumn?.CellIndicatorImage is Image image) + { + int pos; + Rectangle textArea; + var righToLeft = DataGridView.RightToLeft == RightToLeft.Yes; - #endregion + 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)); + } + + // Cell display text + TextRenderer.DrawText(graphics, _selectedItemText, cellStyle.Font, textArea, cellStyle.ForeColor, + KryptonDataGridViewUtilities.ComputeTextFormatFlagsForCellStyleAlignment(righToLeft, cellStyle.Alignment, cellStyle.WrapMode)); + } + } - #region Protected /// /// 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. @@ -391,8 +433,8 @@ protected override Rectangle GetErrorIconBounds(Graphics graphics, DataGridViewC /// protected override Size GetPreferredSize(Graphics graphics, DataGridViewCellStyle cellStyle, int rowIndex, Size constraintSize) { - return DataGridView == null - ? new Size(-1, -1) + return DataGridView == null + ? new Size(-1, -1) : base.GetPreferredSize(graphics, cellStyle, rowIndex, constraintSize); } #endregion @@ -401,31 +443,6 @@ protected override Size GetPreferredSize(Graphics graphics, DataGridViewCellStyl private KryptonDataGridViewComboBoxEditingControl? EditingComboBox => DataGridView!.EditingControl as KryptonDataGridViewComboBoxEditingControl; - private static Rectangle GetAdjustedEditingControlBounds(Rectangle editingControlBounds, - DataGridViewCellStyle cellStyle) - { - // Adjust the vertical location of the editing control: - var preferredHeight = _paintingComboBox!.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 void OnCommonChange() { if (DataGridView is { IsDisposed: false, Disposing: false }) @@ -445,9 +462,6 @@ private bool OwnsEditingComboBox(int rowIndex) => rowIndex != -1 && DataGridView is { EditingControl: KryptonDataGridViewComboBoxEditingControl control } && (rowIndex == ((IDataGridViewEditingControl)control).EditingControlRowIndex); - - private static bool PartPainted(DataGridViewPaintParts paintParts, DataGridViewPaintParts paintPart) => (paintParts & paintPart) != 0; - #endregion #region Internal @@ -525,13 +539,126 @@ internal void SetValueMember(int rowIndex, string value) internal void SetDataSource(int rowIndex, object? value) { + // Force a reread of the cell value and paint when the datasource changes + ResetInitialSelectedItemText(); + _dataSource = value; if (OwnsEditingComboBox(rowIndex)) { EditingComboBox!.DataSource = value; } } + + /// + /// Type casted version of OwningColumn + /// + internal KryptonDataGridViewComboBoxColumn? KryptonOwningColumn => OwningColumn as KryptonDataGridViewComboBoxColumn; #endregion + + /// + /// Resets the inital selected item text. + /// + internal void ResetInitialSelectedItemText() + { + _selectedItemText = string.Empty; + _initialSelectedTextSet = false; + } + + /// + /// Sets the initial item text fetch from the cell value.
+ /// If the cell has a datasource connected this routine retrieves the value that should be shown in the cell. Which usually is the DisplayMember value.
+ /// If the items for the combo are supplied via the Items property, the cell value is checked to exist in the list for input consistency. + ///
+ /// + /// + /// + internal bool SetInitialSelectedItemText(int rowIndex) + { + var value = GetValue(rowIndex); + bool result = true; + var dataSource = KryptonOwningColumn?.DataSource; + + // Documentation describing the behaviour for DisplayMember and ValueMember + // https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.datagridviewcomboboxcolumn?view=windowsdesktop-9.0 + + if (value is not (DBNull or null) + && dataSource is not null + && ValueMember.Length > 0) + { + BindingMemberInfo bindingMemberInfo = new(ValueMember); + + if (DataGridView is not null + && DataGridView.BindingContext is not null + && DataGridView.BindingContext[dataSource, bindingMemberInfo.BindingPath] is CurrencyManager currencyManager + && currencyManager.List is IBindingList bindinglist + && bindinglist.SupportsSearching) + { + if (currencyManager.GetItemProperties().Find(bindingMemberInfo.BindingField, true) is PropertyDescriptor propertyDescriptor) + { + // Define the field used for displaymember. + // If DisplayMember is not set, Valuemember will be used for both. + var displayMember = DisplayMember.Length > 0 + ? DisplayMember + : ValueMember; + + // Find the index of the row that contains propertyDescriptor having value. + // The search stops on the first occurrence. + int index = bindinglist.Find(propertyDescriptor, value); + + if (index != -1 + && currencyManager.List[index] is System.Data.DataRowView dataRowView) + { + try + { + _selectedItemText = dataRowView[displayMember].ToString() ?? string.Empty; + } + catch + { + // Member is an unknow column + throw new ArgumentException($"The field '{displayMember}' specified as '{(DisplayMember.Length > 0 ? "DisplayMember" : "ValueMember")}' has not been found in the data source."); + } + } + else + { + // The row containing the given value was not found. + // Meaning there's a value mismatch between the combobox datasource and the cell value. + throw new ArgumentException($"The property descriptor '{propertyDescriptor.DisplayName}' having value '{value}' was not found in the data source."); + } + } + else + { + throw new ArgumentException($"The field '{ValueMember}' specified as ValueMember has not been found in the data source."); + } + } + else + { + _selectedItemText = string.Empty; + } + } + else if (value is not (DBNull or null) + && dataSource is null + && KryptonOwningColumn?.Items.Count > 0) + { + // DataSource is null and Items is populated + var valueStr = value.ToString(); + + if (valueStr is not null + && KryptonOwningColumn.Items.IndexOf(valueStr) == -1) + { + // The value was not found in the list + throw new ArgumentException($"The cell value {valueStr} was not found in the list with drop-down items."); + } + + _selectedItemText = valueStr ?? string.Empty; + } + else + { + _selectedItemText = value?.ToString() ?? string.Empty; + result = false; + } + + return result; + } } } diff --git a/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewComboBoxColumn.cs b/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewComboBoxColumn.cs index 289051f0c..4ab0424f0 100644 --- a/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewComboBoxColumn.cs +++ b/Source/Krypton Components/Krypton.Toolkit/Controls Toolkit/KryptonDataGridViewComboBoxColumn.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), Giduac & Ahmed Abdelhameed et al. 2017 - 2024. 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 @@ -30,6 +30,14 @@ public KryptonDataGridViewComboBoxColumn() { Items = []; AutoCompleteCustomSource = []; + _kryptonDataGridViewCellIndicatorImage = new(); + } + + /// + protected override void OnDataGridViewChanged() + { + _kryptonDataGridViewCellIndicatorImage.DataGridView = DataGridView as KryptonDataGridView; + base.OnDataGridViewChanged(); } /// @@ -77,8 +85,7 @@ public override object Clone() /// [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public override DataGridViewCell? CellTemplate - { + public override DataGridViewCell? CellTemplate { get => base.CellTemplate; set @@ -113,8 +120,7 @@ public override DataGridViewCell? CellTemplate [Description(@"Controls the appearance and functionality of the KryptonComboBox.")] [DefaultValue(ComboBoxStyle.DropDown)] [RefreshProperties(RefreshProperties.Repaint)] - public ComboBoxStyle DropDownStyle - { + public ComboBoxStyle DropDownStyle { get => ComboBoxCellTemplate?.DropDownStyle ?? throw new InvalidOperationException(@"Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); @@ -155,8 +161,7 @@ public ComboBoxStyle DropDownStyle [Description(@"The maximum number of entries to display in the drop-down list.")] [Localizable(true)] [DefaultValue(8)] - public int MaxDropDownItems - { + public int MaxDropDownItems { get => ComboBoxCellTemplate?.MaxDropDownItems ?? throw new InvalidOperationException(@"Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); @@ -198,8 +203,7 @@ public int MaxDropDownItems [EditorBrowsable(EditorBrowsableState.Always)] [DefaultValue(200)] [Browsable(true)] - public int DropDownHeight - { + public int DropDownHeight { get => ComboBoxCellTemplate?.DropDownHeight ?? throw new InvalidOperationException(@"Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); @@ -241,8 +245,7 @@ public int DropDownHeight [EditorBrowsable(EditorBrowsableState.Always)] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] - public int DropDownWidth - { + public int DropDownWidth { get => ComboBoxCellTemplate?.DropDownWidth ?? throw new InvalidOperationException(@"Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); @@ -296,8 +299,7 @@ public int DropDownWidth [DefaultValue(AutoCompleteMode.None)] [EditorBrowsable(EditorBrowsableState.Always)] [Browsable(true)] - public AutoCompleteMode AutoCompleteMode - { + public AutoCompleteMode AutoCompleteMode { get => ComboBoxCellTemplate?.AutoCompleteMode ?? throw new InvalidOperationException(@"Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); @@ -338,8 +340,7 @@ public AutoCompleteMode AutoCompleteMode [DefaultValue(AutoCompleteSource.None)] [EditorBrowsable(EditorBrowsableState.Always)] [Browsable(true)] - public AutoCompleteSource AutoCompleteSource - { + public AutoCompleteSource AutoCompleteSource { get => ComboBoxCellTemplate?.AutoCompleteSource ?? throw new InvalidOperationException(@"Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate."); @@ -381,8 +382,7 @@ public AutoCompleteSource AutoCompleteSource [TypeConverter(@"System.Windows.Forms.Design.DataMemberFieldConverter")] [Editor(@"System.Windows.Forms.Design.DataMemberFieldEditor", typeof(UITypeEditor))] [DefaultValue(@"")] - public string DisplayMember - { + public string DisplayMember { get => ComboBoxCellTemplate == null ? throw new InvalidOperationException(@"Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate.") @@ -400,13 +400,14 @@ public string DisplayMember if (DataGridView != null) { // Update all the existing KryptonDataGridViewComboBoxCell cells in the column accordingly. + DataGridViewRow dataGridViewRow; DataGridViewRowCollection dataGridViewRows = DataGridView.Rows; var rowCount = dataGridViewRows.Count; for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) { // Be careful not to unshare rows unnecessarily. // This could have severe performance repercussions. - DataGridViewRow dataGridViewRow = dataGridViewRows.SharedRow(rowIndex); + dataGridViewRow = dataGridViewRows.SharedRow(rowIndex); if (dataGridViewRow.Cells[Index] is KryptonDataGridViewComboBoxCell dataGridViewCell) { dataGridViewCell.SetDisplayMember(rowIndex, value); @@ -426,8 +427,7 @@ public string DisplayMember [TypeConverter(@"System.Windows.Forms.Design.DataMemberFieldConverter")] [Editor(@"System.Windows.Forms.Design.DataMemberFieldEditor", typeof(UITypeEditor))] [DefaultValue(@"")] - public string ValueMember - { + public string ValueMember { get => ComboBoxCellTemplate == null ? throw new InvalidOperationException(@"Operation cannot be completed because this DataGridViewColumn does not have a CellTemplate.") @@ -445,13 +445,14 @@ public string ValueMember if (DataGridView != null) { // Update all the existing KryptonDataGridViewComboBoxCell cells in the column accordingly. + DataGridViewRow dataGridViewRow; DataGridViewRowCollection dataGridViewRows = DataGridView.Rows; var rowCount = dataGridViewRows.Count; for (var rowIndex = 0; rowIndex < rowCount; rowIndex++) { // Be careful not to unshare rows unnecessarily. // This could have severe performance repercussions. - DataGridViewRow dataGridViewRow = dataGridViewRows.SharedRow(rowIndex); + dataGridViewRow = dataGridViewRows.SharedRow(rowIndex); if (dataGridViewRow.Cells[Index] is KryptonDataGridViewComboBoxCell dataGridViewCell) { dataGridViewCell.SetValueMember(rowIndex, value); @@ -470,8 +471,7 @@ public string ValueMember [TypeConverter(@"System.Windows.Forms.Design.DataSourceConverter")] [Editor(@"System.Windows.Forms.Design.DataSourceListEditor", typeof(UITypeEditor))] [DefaultValue(null)] - public object? DataSource - { + public object? DataSource { get => ComboBoxCellTemplate == null @@ -487,6 +487,21 @@ public object? DataSource // Update the template cell so that subsequent cloned cells use the new value. ComboBoxCellTemplate.DataSource = value; + + if (DataGridView is not null) + { + DataGridViewRow dataGridViewRow; + DataGridViewRowCollection dataGridViewRows = DataGridView.Rows; + int rowCount = dataGridViewRows.Count; + for (int rowIndex = 0; rowIndex < rowCount; rowIndex++) + { + dataGridViewRow = dataGridViewRows.SharedRow(rowIndex); + if (dataGridViewRow.Cells[Index] is KryptonDataGridViewComboBoxCell dataGridViewCell) + { + dataGridViewCell.DataSource = value; + } + } + } } } #endregion @@ -496,8 +511,18 @@ public object? DataSource /// Small utility function that returns the template cell as a KryptonDataGridViewComboBoxCell /// private KryptonDataGridViewComboBoxCell? ComboBoxCellTemplate => CellTemplate as KryptonDataGridViewComboBoxCell; + // Cell indicator image instance + private KryptonDataGridViewCellIndicatorImage _kryptonDataGridViewCellIndicatorImage; #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 + } } \ No newline at end of file