开发者

Need a faster DataGridView bulk edit method

This is what I'm currently using to implement a "Check all" feature on a bound DataGridView:

int max = ((DataTable)dataGridRes.DataSource).Rows.Count;
for (int i = 0; i < max; i++)
{
    if(((DataTable)dataGridRes.DataSource).Rows[i].Field<long>(0) == 0)
        ((DataTable)dataGridRes.DataSource).R开发者_JS百科ows[i].SetField(0, 1);
}

However this code is hopelessly slow. On a 625 row DataTable it takes aprox 5 seconds to complete on my computer. Very unacceptable.

What am I doing wrong? What better way can I use to do bulk edits on a DataGridView?


This blog has what you need: DataGridView CheckBox Select All

Code posted for posterity:

public delegate void CheckBoxClickedHandler(bool state);
public class DataGridViewCheckBoxHeaderCellEventArgs : EventArgs
{
    bool _bChecked;
    public DataGridViewCheckBoxHeaderCellEventArgs(bool bChecked)
    {
        _bChecked = bChecked;
    }
    public bool Checked
    {
        get { return _bChecked; }
    }
}

class DatagridViewCheckBoxHeaderCell : DataGridViewColumnHeaderCell
{
    Point checkBoxLocation;
    Size checkBoxSize;
    bool _checked = false;
    Point _cellLocation = new Point();
    System.Windows.Forms.VisualStyles.CheckBoxState _cbState =
        System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal;

    public event CheckBoxClickedHandler OnCheckBoxClicked;

    public DatagridViewCheckBoxHeaderCell()
    {
    }

    protected override void Paint(System.Drawing.Graphics graphics,
        System.Drawing.Rectangle clipBounds,
        System.Drawing.Rectangle cellBounds,
        int rowIndex,
        DataGridViewElementStates dataGridViewElementState,
        object value,
        object formattedValue,
        string errorText,
        DataGridViewCellStyle cellStyle,
        DataGridViewAdvancedBorderStyle advancedBorderStyle,
        DataGridViewPaintParts paintParts)
    {
        base.Paint(graphics, clipBounds, cellBounds, rowIndex,
            dataGridViewElementState, value,
            formattedValue, errorText, cellStyle,
            advancedBorderStyle, paintParts);

        Point p = new Point();

        Size s = CheckBoxRenderer.GetGlyphSize(graphics,
            System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal);

        p.X = cellBounds.Location.X +
            (cellBounds.Width / 2) - (s.Width / 2);
        p.Y = cellBounds.Location.Y +
            (cellBounds.Height / 2) - (s.Height / 2);

            _cellLocation = cellBounds.Location;
            checkBoxLocation = p;
            checkBoxSize = s;
        if (_checked)
            _cbState = System.Windows.Forms.VisualStyles.
            CheckBoxState.CheckedNormal;
        else
            _cbState = System.Windows.Forms.VisualStyles.
            CheckBoxState.UncheckedNormal;
            CheckBoxRenderer.DrawCheckBox
            (graphics, checkBoxLocation, _cbState);
    }

    protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
    {
        Point p = new Point(e.X + _cellLocation.X, e.Y + _cellLocation.Y);
        if (p.X >= checkBoxLocation.X && p.X <=
            checkBoxLocation.X + checkBoxSize.Width
            && p.Y >= checkBoxLocation.Y && p.Y <=
            checkBoxLocation.Y + checkBoxSize.Height)
        {
        _checked = !_checked;
        if (OnCheckBoxClicked != null)
        {
            OnCheckBoxClicked(_checked);
            this.DataGridView.InvalidateCell(this);
        }
    }
    base.OnMouseClick(e);
  }
}

The code to add the checkbox to header and the corresponding event code is given below.

private void FormatGrid()
{
    DataView dv = new DataView();
    dv.Table = _loginDs.Tables[0];

    DataGridViewCheckBoxColumn chkbox = new DataGridViewCheckBoxColumn();
    DatagridViewCheckBoxHeaderCell chkHeader = new DatagridViewCheckBoxHeaderCell();
    chkbox.HeaderCell = chkHeader;
    chkHeader.OnCheckBoxClicked += new CheckBoxClickedHandler(chkHeader_OnCheckBoxClicked);
    _chkBoxGrid.Columns.Add(chkbox);

    DataGridViewTextBoxColumn uname = new DataGridViewTextBoxColumn();
    uname.HeaderText = "user";
    uname.Name = "username";
    uname.DataPropertyName = "username";
    _chkBoxGrid.Columns.Add(uname);

    _chkBoxGrid.DataSource = dv;
}

void chkHeader_OnCheckBoxClicked(bool state)
{
    foreach (DataGridViewRow row in _chkBoxGrid.Rows)
        row.Cells[0].Value = state;

}


I found a way to speed it up to an acceptable performance. Essentially unbind the control, do the update on the DataTable and rebind it.

DataTable dt = (DataTable)dataGridRes.DataSource;
dataGridRes.DataSource = null;

for (int i = 0; i < dt.Rows.Count; i++)
    dt.Rows[i].SetField(0, 1);

dataGridRes.DataSource = dt;


Second try.

  1. You are casting way too many times
  2. You are doing an if statement that doesn't matter

try something like:

foreach(DataRow r in ((DataTable)dataGridRes.DataSource).Rows)
{
    r.SetField(0, 1);
}


When editing multiple rows or columns in a DataTable, call BeginLoadData 1st and then call EndLoadData when you're done.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜