Отрисовка грида в виртуальном режиме

Язык Visual Basic на платформе .NET.

Модераторы: Ramzes, Sebas

sergey-911
Постоялец
Постоялец
 
Сообщения: 545
Зарегистрирован: 17.01.2005 (Пн) 19:10

Отрисовка грида в виртуальном режиме

Сообщение sergey-911 » 13.06.2011 (Пн) 10:45

Доброго времени суток уважаемые.
Пишу проект на VB.NET. Мне необходимо отобразить выборку склада производственного предприятия из БД за год. Все бы ничего, да вот только записей при этом выводится около 50 000. При отрисовки гридом набора записей, соответственно, начинаются жуткие тормоза. Таблицу заполняю следующим кодом:

Код: Выделить всё
        'Настройка грида
        DataGridView1.ReadOnly = True
        DataGridView1.AllowUserToAddRows = False
        DataGridView1.AllowUserToDeleteRows = False
        DataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader
        DataGridView1.MultiSelect = False

        'Создание подключения
        Dim strCon As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=.\technology.mdb;"
        Dim cn As New System.Data.OleDb.OleDbConnection(strCon)
        'Создание объекта Command
        Dim strSQL As String = "SELECT * FROM vw_Izd"
        Dim cmdDocuments As New System.Data.OleDb.OleDbCommand(strSQL, cn)

        'Выполнение запроса
        Dim Reader As System.Data.OleDb.OleDbDataReader
        cn.Open()
        Reader = cmdDocuments.ExecuteReader()



Тормозит отрисовка грида здесь:
Код: Выделить всё
        'Отрисовка данных в гриде
        Dim tbl As New DataTable("Table")
        tbl.Load(Reader)
        cn.Close()
        DataGridView1.DataSource = tbl


В статье
http://www.rsdn.ru/article/dotnet/DataGridView20.xml

Упоминается, что DataGridView может использоваться в виртуальном режиме. При этом данные из БД будут подтягиваться по мере необходимости, не загружая ресурсов. Много гуглил, так и не смог реализовать данный механизм.
Уважаемые, помогите плиз реализовать сей механизм, либо еще какой, чтобы данные выводились быстро. Ведь в VB6.0 такой проблемы не было. :(

Прошу прощения за "избитую" тему :oops:
С уважением, Сергей.

Sector
Новичок
Новичок
 
Сообщения: 44
Зарегистрирован: 26.10.2004 (Вт) 14:43

Re: Отрисовка грида в виртуальном режиме

Сообщение Sector » 14.06.2011 (Вт) 12:37

DataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader можно попробовать отключить данную опцию - она сильно замедляет отрисовку при наличии большого количества строк. Нужно выставить фиксированную ширину. Прошу прощения за паллиативное решение.

sergey-911
Постоялец
Постоялец
 
Сообщения: 545
Зарегистрирован: 17.01.2005 (Пн) 19:10

Re: Отрисовка грида в виртуальном режиме

Сообщение sergey-911 » 14.06.2011 (Вт) 20:22

Спасибо Sector. Однако отключение свойства AutoSizeColumnsMode стандартного грида процесс не ускорило. Зато ускорил коммерческий грид DevExpress 2010.2.8. Но всеже, задержка в пару сек. происходит. :shock:
С уважением, Сергей.

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Отрисовка грида в виртуальном режиме

Сообщение Nord777 » 15.06.2011 (Ср) 14:27

sergey-911 писал(а):В статье
http://www.rsdn.ru/article/dotnet/DataGridView20.xml

Упоминается, что DataGridView может использоваться в виртуальном режиме. При этом данные из БД будут подтягиваться по мере необходимости, не загружая ресурсов. Много гуглил, так и не смог реализовать данный механизм.

В той статье есть пример использования. В чём проблема? В переводе на VB.Net?
Там же, чуть ниже есть ссылка с примером на VB.Net
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Отрисовка грида в виртуальном режиме

Сообщение Twister » 16.06.2011 (Чт) 8:51

Зато ускорил коммерческий грид DevExpress 2010.2.8. Но всеже, задержка в пару сек. происходит.
Несколько секунд это очень хороший результат для 50000 записей.

Но, позвольте спросить, какому Юлию Цезарю понадобится видеть в гриде сразу столько данных? Мой опыт говорит, что пользователи при поиске информации всегда стараются по максимуму использовать фильтрацию, чтобы сразу отсечь ненужные данные. Никто и никода не будет просматривать даже сотню записей, если есть возможность установить фильтры на значения полей и ограничить выборку до трёх-четырёх строк.

Так же во многих коммерческих продуктах установлен лимит на количество возвращаемых в грид записей (исходя из вышеописанных мной аргументов). У нас, к примеру, 5000 записей. Это экономит интернет-трафик и даёт еще кучу полезностей.
А я все практикую лечение травами...

sergey-911
Постоялец
Постоялец
 
Сообщения: 545
Зарегистрирован: 17.01.2005 (Пн) 19:10

Re: Отрисовка грида в виртуальном режиме

Сообщение sergey-911 » 17.06.2011 (Пт) 6:43

Спасибо Nord777 , но в статье http://www.rsdn.ru/article/dotnet/DataGridView20.xml пример не связан с БД:
Код: Выделить всё
using System.Collections.Generic;
using System.ComponentModel;
using System.Windows.Forms;

namespace WindowsApplication1
{
  public partial class Form1 : Form
  {
    public Form1()
    {
      ((ISupportInitialize)_grid).BeginInit();
      _grid.VirtualMode = true;
      _grid.CellValueNeeded += _dataGridView_CellValueNeeded;
      _grid.CellValuePushed += _dataGridView_CellValuePushed;
      _grid.Dock = DockStyle.Fill;
      // формируем 26 колонок с именами, соответствующими
      // буквам латинского алфавита
      for (int i = 0; i < 'Z' - 'A'; i++)
      {
        string name = ((char)('A' + i)).ToString();
        _grid.Columns.Add(name, name);
      }

      _grid.RowCount = ushort.MaxValue;

      Controls.Add(_grid);
      ((ISupportInitialize)_grid).EndInit();
    }

    DataGridView _grid = new DataGridView();
    // хеш-таблица, хранящая данные заполненных ячеек
    Dictionary<int, object> _values = new Dictionary<int, object>();

    // вычисляет ключ по значениям индексов строки и колонки
    static int CalcKey(int rowIndex, int columnIndex)
    {
      return rowIndex + (columnIndex << 16);
    }

    // обработчик события, генерируемого при запросе данных grid-ом
    private void _dataGridView_CellValueNeeded(
      object sender, DataGridViewCellValueEventArgs e)
    {
      object value;

      if (_values.TryGetValue(CalcKey(e.RowIndex, e.ColumnIndex), out value))
        e.Value = value;
    }

    // обработчик события, генерируемого при изменении данных ячейки
    private void _dataGridView_CellValuePushed(
      object sender, DataGridViewCellValueEventArgs e)
    {
      _values[CalcKey(e.RowIndex, e.ColumnIndex)] = e.Value;
    }
  }
}

Да и C# я плохо знаю, а перевести с помощью сайтов - конвертеров, к примеру http://kbyte.ru/ru/Services/Converter.aspx или http://www.developerfusion.com/tools/convert/vb-to-csharp/ не получается корректно даже данный пример, без подключения к БД.
Буду признателен за рабочий пример и за любую помощь.
Что касается замечания Twister, то я конечно с ним согласен, но в данном случае необходимо выводить все материалы склада.
С уважением, Сергей.

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Отрисовка грида в виртуальном режиме

Сообщение Twister » 17.06.2011 (Пт) 7:43

Что касается замечания Twister, то я конечно с ним согласен, но в данном случае необходимо выводить все материалы склада.
Материалы склада обычно выводятся в виде дерева (по категориям). И правила, о которых я говорил выше, более чем применимы и к такому дереву. Разве кладовщику нужно видеть сразу все 50000 номенклатур? Он что, их все за раз может оприходовать или списать?

В дерево Вы можете подгружать child nod'ы по мере необходимости. Это, опять же, повысит скорость и снизит сетевой трафик.

Другое дело, если требуется экспортировать такой объём данных в отчёт о состоянии склада. Там да, это может быть действительно нужно.
А я все практикую лечение травами...

sergey-911
Постоялец
Постоялец
 
Сообщения: 545
Зарегистрирован: 17.01.2005 (Пн) 19:10

Re: Отрисовка грида в виртуальном режиме

Сообщение sergey-911 » 19.06.2011 (Вс) 21:34

Twister, действительно нужно отобразить большой объем в гриде - просьба заказчика. :shock:
Nord777, в примере http://msdn.microsoft.com/en-us/library/2b177d6d(VS.80).aspx формируется грид записями из кэша, если я все правильно понял. Как аналогично загрузить данными из БД - я не сообразил. :( Как в данном случае написать процедуру dataGridView1_CellValueNeeded - тоже. :oops:
Буду очень признателен - если подправите пример, находящийся в аттаче. В нем из БД Access загружается в dataGridView 30 000 записей. :oops:
Вложения
Отрисовка DataGridView в виртуальном режиме.rar
Отрисовка DataGridView в виртуальном режиме
(199.22 Кб) Скачиваний: 142
С уважением, Сергей.

Twister
Теоретик
Теоретик
Аватара пользователя
 
Сообщения: 2251
Зарегистрирован: 28.06.2005 (Вт) 12:32
Откуда: Алматы

Re: Отрисовка грида в виртуальном режиме

Сообщение Twister » 20.06.2011 (Пн) 6:47

sergey-911 писал(а):Twister, действительно нужно отобразить большой объем в гриде - просьба заказчика. :shock:

Ну, тогда я могу лишь искренне посочувствовать, ибо заказчик зачастую вообще слабо представляет чего хочет. Реже встречаются те, которые примерно знают чего хотят, но и они не имеют ни малейшего представления о производительности и эффективности того или иного решения. Во всех конторах (включая мой собственный бизнес), в которых я работал, ни одно пожелание заказчика не будет утверждено до одобрения программистом. И Вам того же желаю!
А я все практикую лечение травами...

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Отрисовка грида в виртуальном режиме

Сообщение Nord777 » 20.06.2011 (Пн) 10:49

sergey-911 мне до сих пор не понятно что именно тебе не ясно.
Пока мне только понятно твоё желание получить готовый код.
Посмотри на этот код:
Код: Выделить всё
Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim ListOfRows As New List(Of clsOneRow)(50000)
        Dim Row As New clsOneRow
        ListOfRows.Add(New clsOneRow() With {.Name = "Иван", .City = "Москва"})
        ListOfRows.Add(New clsOneRow() With {.Name = "Александр", .City = "Питербург"})
        ListOfRows.Add(New clsOneRow() With {.Name = "Федор", .City = "Тула"})
        ListOfRows.Add(New clsOneRow() With {.Name = "Илья", .City = "Донецк"})
        DataGridView1.DataSource = ListOfRows
    End Sub

    Private Class clsOneRow
        Private _City As String
        Private _Name As String

        Public Property Name() As String
            Get
                Return _Name
            End Get
            Set(ByVal value As String)
                _Name = value
            End Set
        End Property

        Public Property City() As String
            Get
                Return _City
            End Get
            Set(ByVal value As String)
                _City = value
            End Set
        End Property
    End Class

End Class

Для тебя является проблемой:
1) изменить под себя класс clsOneRow :?:
2) Заполнить при помощи Reader'a список ListOfRows данными из твоей базы :?:
3) В событии dataGridView1_CellValueNeeded подставить необходимые данные из ListOfRows :?:
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

sergey-911
Постоялец
Постоялец
 
Сообщения: 545
Зарегистрирован: 17.01.2005 (Пн) 19:10

Re: Отрисовка грида в виртуальном режиме

Сообщение sergey-911 » 20.06.2011 (Пн) 18:55

Извини Nord777 за навязчивость, я не могу связать твой код

Код: Выделить всё
Public Class Form1

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Dim ListOfRows As New List(Of clsOneRow)(50000)
        Dim Row As New clsOneRow
        ListOfRows.Add(New clsOneRow() With {.Name = "Иван", .City = "Москва"})
        ListOfRows.Add(New clsOneRow() With {.Name = "Александр", .City = "Питербург"})
        ListOfRows.Add(New clsOneRow() With {.Name = "Федор", .City = "Тула"})
        ListOfRows.Add(New clsOneRow() With {.Name = "Илья", .City = "Донецк"})
        DataGridView1.DataSource = ListOfRows
    End Sub

    Private Class clsOneRow
        Private _City As String
        Private _Name As String

        Public Property Name() As String
            Get
                Return _Name
            End Get
            Set(ByVal value As String)
                _Name = value
            End Set
        End Property

        Public Property City() As String
            Get
                Return _City
            End Get
            Set(ByVal value As String)
                _City = value
            End Set
        End Property
    End Class

End Class


с кодом заполнения из БД

Код: Выделить всё
        Dim strCon As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Documents and Settings\Sergey\Мои документы\Projects\Отрисовка DataGridView в виртуальном режиме\Отрисовка DataGridView в виртуальном режиме\bin\Debug\DataGridView.mdb;"
        'Заполняем грид данными из БД
        Cursor = Cursors.WaitCursor
        'Запрещаем правку в гриде
        DataGridView1.ReadOnly = True
        DataGridView1.AllowUserToAddRows = False
        DataGridView1.AllowUserToDeleteRows = False
        DataGridView1.VirtualMode = True
        DataGridView1.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.AllCellsExceptHeader
        DataGridView1.MultiSelect = False
        'Создание подключения
        Dim cn As New System.Data.OleDb.OleDbConnection(strCon)
        'Создание объекта Command
        Dim strSQL As String = "SELECT * FROM vw_DataGridView"
        Dim cmdDocuments As New System.Data.OleDb.OleDbCommand(strSQL, cn)
        'Создание объекта tbl
        Dim Reader As System.Data.OleDb.OleDbDataReader
        cn.Open()
        Reader = cmdDocuments.ExecuteReader()
        Dim tbl As New DataTable("Table")
        tbl.Load(Reader)
        cn.Close()
        'Заполняем грид
        DataGridView1.DataSource = tbl
        Cursor = Cursors.Default


Я окончательно запутался. Нашел милион примеров, в которых грид заполняется из кэша. А как заполнить грид из БД и при этом не пихать все записи в DataGridView, а оставить их в RecordSet, в DataGridView же грузить только те записи, которые умещаются на его видимой части, а при прокрутке подгружать новые/выгружать старые? :(
С уважением, Сергей.

Nord777
Гуру
Гуру
Аватара пользователя
 
Сообщения: 1144
Зарегистрирован: 22.02.2004 (Вс) 13:15
Откуда: Подольск

Re: Отрисовка грида в виртуальном режиме

Сообщение Nord777 » 20.06.2011 (Пн) 19:59

Так понятней?
Код: Выделить всё
Imports System.Data.OleDb
Public Class Form1
   Private Const CacheSize% = 50000
   Dim ListOfRows As New List(Of clsOneRow)(CacheSize)

   Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
      DataGridView1.VirtualMode = True
      DataGridView1.AllowUserToDeleteRows = False
      'Добавить две колонки
      DataGridView1.Columns.Add("C1", "C1") : DataGridView1.Columns.Add("C2", "C2")
      DataGridView1.Rows.AddCopies(0, CacheSize)
      LoadIntoCache()
   End Sub

   Private Sub LoadIntoCache()
      Dim conStr$ = "Provider=Microsoft.ACE.OLEDB..................."
      Dim selStr$ = "SELECT AnyTextField1, AnyTextField2 FROM AnyTable"
      Dim Reader As OleDbDataReader

      Using OLEDBCon As New OleDbConnection(conStr)
         OLEDBCon.Open()
         Using OleDbCom As New OleDbCommand(selStr, OLEDBCon)
            Reader = OleDbCom.ExecuteReader(CommandBehavior.CloseConnection)
            Do While Reader.Read
               ListOfRows.Add(New clsOneRow(Reader))
            Loop
            Reader.Close()
         End Using
         OLEDBCon.Close()
      End Using
   End Sub

   Private Sub DataGridView1_CellValueNeeded(ByVal sender As Object, ByVal e As System.Windows.Forms.DataGridViewCellValueEventArgs) Handles DataGridView1.CellValueNeeded
      Select Case e.ColumnIndex
         Case 0
            e.Value = ListOfRows(e.RowIndex).C1
         Case 1
            e.Value = ListOfRows(e.RowIndex).C2
      End Select
   End Sub

   Private Class clsOneRow
      Private _C1 As String
      Private _C2 As String

      Public Sub New(ByVal Reader As OleDbDataReader)
         _C1 = Reader.GetString(0)
         _C2 = Reader.GetString(1)
      End Sub
      Public ReadOnly Property C1() As String
         Get
            Return _C1
         End Get
      End Property
      Public ReadOnly Property C2() As String
         Get
            Return _C2
         End Get
      End Property
   End Class

End Class
Microsoft Visual Studio 2008
Microsoft .NET Framework 3.5

sergey-911
Постоялец
Постоялец
 
Сообщения: 545
Зарегистрирован: 17.01.2005 (Пн) 19:10

Re: Отрисовка грида в виртуальном режиме

Сообщение sergey-911 » 21.06.2011 (Вт) 20:21

Спасибо Nord777, респект тебе и уважуха! :D Работает! :D
С уважением, Сергей.


Вернуться в Visual Basic .NET

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

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

    TopList