Оптимизация выделения DataGridView

Язык C#: программирование на C#, портирование кода C# на VB и VB на C#.

Модератор: Ramzes

DirectXManiac
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1543
Зарегистрирован: 03.11.2005 (Чт) 13:32
Откуда: из DirectX SDK

Оптимизация выделения DataGridView

Сообщение DirectXManiac » 19.10.2010 (Вт) 9:47

Привет всем! Опишу проблему: есть контрол:
Код: Выделить всё
public class BinEditor : DataGridView

Он связан с другими контролами(графиками). Если я выделяю в гриде - у меня выделяется в графике, и наоборот. Проблема состоит в следующем: когда выделение происходит в гриде - все отрабатывает на УРА, а вот наборот когда выделение переходит в грид все и тормозит. Совмещение выделенного происходит через свойство грида:
Код: Выделить всё
public List<int> SelectionAddress
        {
            get
            {
                List<int> addrs = new List<int>();
                foreach (DataGridViewCell cell in SelectedCells)
                {
                    if (mPrecision == BinPrecision.Precision_8bit)
                        addrs.Add(AddressOffset + (cell.RowIndex * numColumns + cell.ColumnIndex));
                    else
                        addrs.Add(AddressOffset + (cell.RowIndex * numColumns + cell.ColumnIndex * 2));
                }
                return addrs;
            }
            set
            {
                try
                {
                    foreach (DataGridViewCell cel in SelectedCells)
                    {
                        this.Rows[cel.RowIndex].Cells[cel.ColumnIndex].Selected = false;
                    }
                    foreach (int address in value)
                    {
                        if (mPrecision == BinPrecision.Precision_8bit)
                        {
                            int row = (address - AddressOffset) / numColumns;
                            int col = (address - AddressOffset) - (row * numColumns);
                            this.Rows[row].Cells[col].Selected = true;
                        }
                        else
                        {
                            int row = (address - AddressOffset) / numColumns / 2;
                            int col = ((address - AddressOffset) - (row * numColumns)) / 2;
                            this.Rows[row].Cells[col].Selected = true;
                        }

                    }
                }
                catch (Exception ex) { }
            }
        }

get использую когда нужно передать выделение в график, а set когда надо установить выделение.
Подскажите как оптимизировать, все тормозит не знаю как исправить?
#define ROFL 0xDDDD

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: Оптимизация выделения DataGridView

Сообщение FireFenix » 19.10.2010 (Вт) 12:22

Не меняя логику - сложно ускорить
Можно заменить For Each на обычный For, но даст небольшой прирост

Ты уверен что именно это место тормозит?
Посмотри ещё места вызова, может функа многократно вызывается при выделении
Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

DirectXManiac
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1543
Зарегистрирован: 03.11.2005 (Чт) 13:32
Откуда: из DirectX SDK

Re: Оптимизация выделения DataGridView

Сообщение DirectXManiac » 19.10.2010 (Вт) 12:31

Едиственное что мне удалось пока сделать это очистку грида ускорить:
Код: Выделить всё
this.ClearSelection()

Нашел таки! :D

Да уверен что тормозит именно здесь! Это прямо видно. Причем когда .Selected = true; сразу перепрорисовывается контрол - из за этого тормоза, как бы происходит DoEvents. Как избежать? М.б. установка каких то стилей поможет?
#define ROFL 0xDDDD

FireFenix
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1640
Зарегистрирован: 25.05.2007 (Пт) 10:24
Откуда: Mugen no Sora

Re: Оптимизация выделения DataGridView

Сообщение FireFenix » 19.10.2010 (Вт) 21:19

Запустил, сделал у себя - действительно медленнее программное выделение, чем через GUI
Стало дико интересно, что там за кривая реализация...

Бродя Рефлектором по коду выяснил, что только приватные секции реализующие выделение инкриминируют переменную Me.inBulkPaintCount += 1 и потом сбрасывают Me.ExitBulkPaint(-1, -1)
Что в свою очередь в событии OnCellStateChanged не даёт вызывать Me.InvalidateCellPrivate
Код: Выделить всё
Protected Overridable Sub OnCellStateChanged(ByVal e As DataGridViewCellStateChangedEventArgs)
'...
    If ((e.StateChanged = DataGridViewElementStates.Selected) AndAlso (Me.inBulkPaintCount = 0)) Then
        Me.InvalidateCellPrivate(dataGridViewCell)
    End If
'...
End Sub

Т.е. при обычном выделении ячейки, каждый раз вызывается Me.InvalidateCellPrivate, а при выделении мышкой - только в конце

Написал класс-обёртку с функой выделения (хак через рефлексию для доступа к приватной функе SelectCellRange :D) + двойная буферизация
Код: Выделить всё
Public Class DGV : Inherits DataGridView
    Public Sub New()
        MyBase.New()
        MyBase.DoubleBuffered = True
    End Sub

    Public Sub SelectCellRange(ByVal columnIndexFrom As Integer, ByVal rowIndexFrom As Integer, ByVal columnIndexTo As Integer, ByVal rowIndexTo As Integer, ByVal [select] As Boolean)
        Dim mi As MethodInfo = GetType(DataGridView).GetMethod("SelectCellRange", System.Reflection.BindingFlags.NonPublic Or System.Reflection.BindingFlags.Instance)

        mi.Invoke(Me, New Object() {columnIndexFrom, rowIndexFrom, columnIndexTo, rowIndexTo, [select]})
    End Sub
End Class


Заполнил DGV ячейками 0...500 и строками 0...500
Протестировал выделение всего диапазона функами:
Код: Выделить всё
    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim Timer As New System.Diagnostics.Stopwatch
        Timer.Start()

        DGV.SelectCellRange(0, 0, 500, 500, True)

        Timer.Stop()
        Console.WriteLine("Reflexion: " & Timer.ElapsedMilliseconds)
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim i As Integer
        Dim j As Integer

        Dim Timer As New System.Diagnostics.Stopwatch
        Timer.Start()

        For i = 0 To 500
            For j = 0 To 500
                DGV.Item(i, j).Selected = True
            Next
        Next

        Timer.Stop()
        Console.WriteLine("Item.Select: " & Timer.ElapsedMilliseconds)
    End Sub

    Private Sub Button3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
        Dim Timer As New System.Diagnostics.Stopwatch
        Timer.Start()

        DGV.SelectAll()

        Timer.Stop()
        Console.WriteLine("SelectAll: " & Timer.ElapsedMilliseconds)
    End Sub


Результат в миллисекундах:
Код: Выделить всё
Reflexion: 241
Reflexion: 256
Reflexion: 199

Item.Select: 422
Item.Select: 468
Item.Select: 418

SelectAll: 171
SelectAll: 180
SelectAll: 158

Почти идеально, время сократилось почти в 2 раза. Ещё можно вынести в тело класса получение MethodInfo, что ещё чуток понизит время выполнения

Думаю, что средствами DataGridView большей скорости не добиться, т.е. либо делать свои костыли, либо искать другие аналоги контрола

P.S. Я сделал на VB, но думаю не составит труда перевести на веб-сервисе в C#
Последний раз редактировалось FireFenix 20.10.2010 (Ср) 10:47, всего редактировалось 1 раз.
Птицей Гермеса меня называют, свои крылья пожирая... сам себя я укрощаю
私はヘルメスの鳥 私は自らの羽根を喰らい 飼い慣らされる

DirectXManiac
Продвинутый гуру
Продвинутый гуру
Аватара пользователя
 
Сообщения: 1543
Зарегистрирован: 03.11.2005 (Чт) 13:32
Откуда: из DirectX SDK

Re: Оптимизация выделения DataGridView

Сообщение DirectXManiac » 20.10.2010 (Ср) 9:51

ОГО! Спасибо. Интересная реализация, вопрос только в том что мне нужно выделять не подряд от и до, а выборочно, для этого foreach. Я всерьез задумался над написанием своего контрола, но все равно спасибо! Код попробую!
#define ROFL 0xDDDD


Вернуться в C#

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7

    TopList  
cron