Замена огромного DataGridViewComboBoxColumn для повышения производительности - PullRequest
1 голос
/ 11 марта 2019

У меня есть диалог с WinForms DataGridView , который показывает список пользователей. Каждая строка содержит комбинированный список AD-User ( DataGridViewComboboxColumn ), который может стать очень большим (10 000+ элементов). Этот DataGridView используется для связи пользователей с соответствующими пользователями AD. Содержимое этого списка не изменяется между рядами.

По соображениям производительности я хочу изменить этот комбинированный список на более масштабируемый.

Я думал об использовании TextBox с маленькой кнопкой выбора. Затем кнопка откроет модальное диалоговое окно для выбора пользователя AD. Ячейка будет содержать выбранный объект AD-User. В качестве альтернативы, это диалоговое окно может также открываться при двойном щелчке на ячейке, но я думаю, что это не очень интуитивно понятно.

Будет ли это лучшим вариантом для замены этого списка? Если у вас есть другие / лучшие способы обработки такого выбора, пожалуйста, дайте мне знать.

И если так: Как я могу создать такую ​​пользовательскую ячейку DataGridView (TextBox + Button)?

1 Ответ

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

Самое простое решение - сделать колонку доступной только для чтения, а затем использовать колонку с кнопками. Затем обработайте CellContentClick событие DataGridView, чтобы обнаружить нажатия кнопки.

Другой вариант - создание настраиваемого столбца на основе DataGridViewButtonColumn. Что-то вроде этого с небольшим изменением показывает значение ячейки вместо текста метки.

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

Пример

Мой выбор основан на столбце DataGridView кнопки для лучшего взаимодействия с пользователем, например, выделение кнопки при перемещении мыши. Для этого я изменю ответ , который показывает, как отображать метку и кнопку в одной ячейке. Здесь я немного его изменяю, чтобы отображать значения ячеек в виде текста метки:

enter image description here

using System.Drawing;
using System.Windows.Forms;
public class DataGridViewLookupColumn : DataGridViewButtonColumn
{
    public DataGridViewLookupColumn()
    {
        CellTemplate = new DataGridViewLookupCell();
        ButtonText = "...";
    }
    public string ButtonText { get; set; }
    public override object Clone()
    {
        var c = (DataGridViewLookupColumn)base.Clone();
        c.ButtonText = this.ButtonText;
        return c;
    }
}
public class DataGridViewLookupCell : DataGridViewButtonCell
{
    protected override void Paint(Graphics graphics, Rectangle clipBounds,
        Rectangle cellBounds, int rowIndex,
        DataGridViewElementStates elementState,
        object value, object formattedValue, string errorText,
        DataGridViewCellStyle cellStyle,
        DataGridViewAdvancedBorderStyle advancedBorderStyle,
        DataGridViewPaintParts paintParts)
    {
        var g = this.DataGridView;
        var c = (DataGridViewLookupColumn)this.OwningColumn;
        base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState,
            value, formattedValue, errorText, cellStyle, advancedBorderStyle,
            DataGridViewPaintParts.All &
            ~DataGridViewPaintParts.ContentBackground &
            ~DataGridViewPaintParts.ContentForeground);
        var cellRectangle = g.GetCellDisplayRectangle(c.Index, rowIndex, false);
        var buttonRectangle = GetContentBounds(rowIndex);
        var textRectangle = new Rectangle(cellRectangle.Location,
            new Size(cellRectangle.Width - GetButtonWidth(),
            cellRectangle.Height));
        buttonRectangle.Offset(cellRectangle.Location);
        var alignment = cellStyle.Alignment;
        cellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
        base.Paint(graphics, clipBounds, buttonRectangle, rowIndex, elementState,
            value, c.ButtonText, errorText, cellStyle, advancedBorderStyle,
            DataGridViewPaintParts.All &
            ~DataGridViewPaintParts.Border);
        cellStyle.Alignment = alignment;
        base.Paint(graphics, clipBounds, textRectangle, rowIndex, elementState,
             value, formattedValue, errorText, cellStyle, advancedBorderStyle,
             DataGridViewPaintParts.ContentForeground);
    }
    protected override Rectangle GetContentBounds(Graphics graphics,
        DataGridViewCellStyle cellStyle, int rowIndex)
    {
        var w = GetButtonWidth();
        var r = base.GetContentBounds(graphics, cellStyle, rowIndex);
        return new Rectangle(r.Right - w, r.Top, w, r.Height);
    }
    private int GetButtonWidth()
    {
        var c = (DataGridViewLookupColumn)this.OwningColumn;
        var text = c.ButtonText;
        return TextRenderer.MeasureText(text, c.DefaultCellStyle.Font).Width
            + 10 /*a bit padding */;
    }
}

Ручка нажатия на кнопку

Чтобы обработать нажатие кнопки, обработайте CellContentClick как обычный DataGridViewColumnButton и проверьте, если e.RowIndex > -1 и e.ColumnIndex == your desired column index:

void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    //if click is on row header or column header, do nothing.
    if(e.RowIndex < 0 || e.ColumnIndex < 0)
        return;

    //Check if click is on specific column 
    if( e.ColumnIndex  == dataGridView1.Columns["specific column name"].Index)
    {
        //Put some logic here, for example show a dialog and use result.
    }
}
...