DataGridViewComboBoxColumn странное поведение, временное изменение размера в CellEnter - PullRequest
0 голосов
/ 07 марта 2019

У меня есть DataGridView с количеством столбцов; один из которых DataGridViewComboBoxColumn. Я установил свой DataGridView.EditMode = EditOnEnter.

Для моих строк задана высота нескольких строк текста, так как это показывает пользователю все доступное пространство для их текста, однако это приводит к временному изменению размера ячейки ComboBox при нажатии.

Вот снимок экрана моей колонки:

ComboBox Column States

Вторая, третья и четвертая ячейки являются высотой строки по умолчанию. Первая ячейка - это состояние ComboBox при первом щелчке по ячейке. Затем вы должны снова щелкнуть (в небольшом поле), чтобы отобразить содержимое ComboBox:

DroppedDown

Похоже, что ComboBox изменяет размеры по высоте текста.

Как только вы покидаете ячейку, она изменяет свой размер до высоты строки по умолчанию:

CellExit behaviour

Как я могу остановить это поведение и заставить ComboBox сохранить его размер равным размеру высоты строки?

1 Ответ

1 голос
/ 13 марта 2019

Это пользовательское поле со списком.Добавьте это в свой проект, и вы можете добавить его в форму Windows и использовать его как обычный ComboBox

CustomComboBox

<ToolboxItem(true)> _
<ToolboxBitmap(GetType(ComboBox))> _
partial public class CustomComboBox
    Inherits ComboBox
    sub New()
        DrawMode = DrawMode.OwnerDrawFixed
        DropDownStyle = ComboBoxStyle.DropDownList

        ItemHeight = 26
        DropDownHeight = ItemHeight * 6
    end sub

    protected Overrides sub OnDrawItem( e As DrawItemEventArgs)
        if (e.Index >= 0) then
            e.DrawBackground()
            e.DrawFocusRectangle()

            using b as New SolidBrush(ForeColor)
                dim name as String = Items(e.Index).ToString()

                dim textLeft as Int32 = e.Bounds.Left + 3
                dim textTop as Int32 = e.Bounds.Top + (e.Bounds.Height / 2) - (Font.Height / 2)
                dim textWidth  as Int32 = e.Bounds.Width - e.Bounds.Width
                dim textHeight  as Int32 = e.Bounds.Height
                Dim textTarget  as Rectangle = new Rectangle(textLeft, textTop, textWidth, textHeight)

                e.Graphics.DrawString(name, Font, b, textTarget)
            end using
        end if
    end sub
End Class

Чтобы изменить высотуComboBox и количество места, выделенного каждому элементу внутри него, измените значение ItemHeight в конструкторе.

enter image description here


Чтобы поместить это в DataGridView, вам нужно создать пользовательскую ячейку, столбец и EditControl.Все три относительно легко создать, как вы можете видеть из кода ниже.

CustomComboBoxCell

public class CustomComboBoxCell 
    Inherits DataGridViewTextBoxCell

    public overrides sub InitializeEditingControl(rowIndex As Int32 , initialFormattedValue As Object , dataGridViewCellStyle As DataGridViewCellStyle )
        ' Set the value of the editing control to the current cell value. 
        mybase.InitializeEditingControl(rowIndex, initialFormattedValue, dataGridViewCellStyle)

        dim ctl as CustomComboBoxEditControl = CType(DataGridView.EditingControl, CustomComboBoxEditControl)
        Dim col As CustomComboBoxColumn = CType(DataGridView.Columns(DataGridView.CurrentCell.ColumnIndex), CustomComboBoxColumn)
        Dim row As DataGridViewRow = CType(DataGridView.Rows(DataGridView.CurrentCell.RowIndex), DataGridViewRow)

        ctl.DataSource = col.DataSource
        ctl.Height = DataGridView.RowTemplate.Height
        ctl.ItemHeight = row.Height - 6

        ' Use the default row value when Value property is null. 
        if (me.Value is Nothing OrElse me.Value is DBNull.Value)
            ctl.Text = me.DefaultNewRowValue
        else
            ctl.Text = me.Value
        end if
    end sub

    public overrides ReadOnly property EditType() As Type
        get
            return GetType(CustomComboBoxEditControl)
        end get
    end Property

    public overrides readonly property FormattedValueType () as Type
        get 
             return GetType(String)
        end get
    end Property

    public overrides ReadOnly property ValueType() As Type
        get
            return GetType(String)
        End Get
    end property

    public overrides ReadOnly property DefaultNewRowValue() as Object
        get
            return String.Empty
        end Get
    end Property

    protected Overrides sub Paint(graphics As Graphics , _
                                  clipBounds As Rectangle , _ 
                                  cellBounds As Rectangle , _
                                  rowIndex As int32 , _
                                  cellState As DataGridViewElementStates , _ 
                                  value As Object , _
                                  formattedValue As Object , _
                                  errorText As String , _
                                  cellStyle As DataGridViewCellStyle , _
                                  advancedBorderStyle As DataGridViewAdvancedBorderStyle , _
                                  paintParts As DataGridViewPaintParts)
        'base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts)
        mybase.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, String.Empty, String.Empty, errorText, cellStyle, advancedBorderStyle, paintParts)

        if (TypeOf value is string)
            Dim valueString As String = Convert.ToString(value)

            if (not String.IsNullOrEmpty(valueString))
                Dim b As Brush = new SolidBrush(cellStyle.ForeColor)

                Dim textLeft as Int32 = cellBounds.Left + 6
                Dim textTop  as Int32 = cellBounds.Top + (cellBounds.Height / 2) - (cellStyle.Font.Height / 2)
                Dim textWidth  as Int32 = cellBounds.Width - cellBounds.Width
                Dim textHeight as Int32 = cellBounds.Height
                Dim textTarget As Rectangle = new Rectangle(textLeft, textTop, textWidth, textHeight)

                graphics.DrawString(valueString, cellStyle.Font, b, textTarget)
            end if
        end if
    end sub
end class

CustomComboBoxColumn

public class CustomComboBoxColumn 
    Inherits DataGridViewColumn

    sub new ()
        mybase.new(New CustomComboBoxCell())
    end sub

    public Property DataSource() as Object

    public overrides property CellTemplate() As DataGridViewCell 
        get
            return mybase.CellTemplate
        end get

        set
            Dim targetType as Type = GetType(CustomComboBoxCell)
            ' Ensure that the cell used for the template is a CustomComboBoxCell. 
            if (not IsNothing(value) AndAlso 
                not value.GetType().IsAssignableFrom(targetType))

                Dim errorMessage As String = $"CellTemplate must be of the type {targetType}."
                throw new InvalidCastException(errorMessage)
            end if

            mybase.CellTemplate = value
        end set
    End Property

    public overrides Function Clone() as Object 
        Dim retVal As CustomComboBoxColumn = CType(mybase.Clone(), CustomComboBoxColumn)
        retVal.DataSource = me.DataSource

        return retVal
    End Function
end class

CustomComboBoxEditControl

<ToolboxItem(false)>
public class CustomComboBoxEditControl 
    Inherits CustomComboBox
    Implements IDataGridViewEditingControl

    public Sub New ()
        IDataGridViewEditingControl_EditingControlFormattedValue = false
    end sub


    Public Property IDataGridViewEditingControl_EditingControlDataGridView As DataGridView Implements IDataGridViewEditingControl.EditingControlDataGridView
    Public Property IDataGridViewEditingControl_EditingControlValueChanged As Boolean Implements IDataGridViewEditingControl.EditingControlValueChanged
    Public Property IDataGridViewEditingControl_EditingControlRowIndex As Integer Implements IDataGridViewEditingControl.EditingControlRowIndex

    Public Function IDataGridViewEditingControl_GetEditingControlFormattedValue(context As DataGridViewDataErrorContexts) As Object Implements IDataGridViewEditingControl.GetEditingControlFormattedValue
        return IDataGridViewEditingControl_EditingControlFormattedValue
    End Function

    Public ReadOnly Property IDataGridViewEditingControl_RepositionEditingControlOnValueChange As Boolean Implements IDataGridViewEditingControl.RepositionEditingControlOnValueChange
        get
            return False
        End Get
    end property

    Public ReadOnly Property IDataGridViewEditingControl_EditingPanelCursor As Cursor Implements IDataGridViewEditingControl.EditingPanelCursor
        get
            Return MyBase.Cursor
        End Get
    end Property

    Public Property IDataGridViewEditingControl_EditingControlFormattedValue As Object Implements IDataGridViewEditingControl.EditingControlFormattedValue
        get
            return me.selectedItem
        End Get
        Set(value As Object)
            me.SelectedItem = value
        End Set
    end property

    Public Sub IDataGridViewEditingControl_ApplyCellStyleToEditingControl(dataGridViewCellStyle As DataGridViewCellStyle) Implements IDataGridViewEditingControl.ApplyCellStyleToEditingControl
        me.Font = dataGridViewCellStyle.Font
        me.ForeColor = dataGridViewCellStyle.ForeColor
        me.BackColor = dataGridViewCellStyle.BackColor
    End Sub

    Public Function IDataGridViewEditingControl_EditingControlWantsInputKey(keyData As Keys, dataGridViewWantsInputKey As Boolean) As Boolean Implements IDataGridViewEditingControl.EditingControlWantsInputKey
        select (keydata and Keys.KeyCode)
            case Keys.Escape, Keys.Up, Keys.Down, Keys.Home, Keys.End, Keys.PageDown, Keys.PageUp
                return true
            Case else
                return Not dataGridViewWantsInputKey
        end Select
    End Function

    Public Sub     IDataGridViewEditingControl_PrepareEditingControlForEdit(selectAll As Boolean) Implements IDataGridViewEditingControl.PrepareEditingControlForEdit
        ' Do nothing
    End Sub

    protected overrides sub OnSelectedValueChanged( eventArgs as EventArgs)
        ' Notify the DataGridView that the contents of the cell have changed.
        Me.IDataGridViewEditingControl_EditingControlValueChanged = true
        Me.IDataGridViewEditingControl_EditingControlDataGridView.NotifyCurrentCellDirty(true)
    end sub
End Class

Затем он добавляется в форму с помощью:

grid.AutoGenerateColumns = false
grid.RowTemplate.Height = 45

Dim customComboBoxColumn as new CustomComboBoxColumn()
customComboBoxColumn.DataPropertyName = "Custom Drop Down"
customComboBoxColumn.DataSource = DropDownItems1
dataGridView1.Columns.Add(customComboBoxColumn)

Dim regularComboBoxColumn as new DataGridViewComboBoxColumn()
regularComboBoxColumn.DataPropertyName = "Regular Drop Down"
regularComboBoxColumn.DataSource = DropDownItems2
dataGridView1.Columns.Add(regularComboBoxColumn)

Вот как это выглядит при размещении в форме,Левая колонка - это новый CustomComboBoxColumn, а справа - стандарт DataGridViewComboBoxColumn

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...