2017-08-08 20 views
0

私は1つの2D配列、つまりx(、)As Objectを使って作業しています。これは、ユーザーが開いた長方形のデータファイルに基づいています。 x(、)の内容は、ほとんどが数値の単精度または倍精度の実数と整数です。したがって、配列は、x(100,100)から例えば100までの次元を有することができる。 x(100000,1000)。VB.NET - DataGridViewのDataSourceであるLarge DataTableを高速に更新するには?

datagridviewは動的に作成され、DGVCREATEクラスの呼び出しを介して更新されます。

datagridviewで使用されるデータソースのサイズを小さくする試みとして、datagridview1.scroll用のAddHandlerがあります。これにより、ユーザーがdatagridviewをスクロールすると、左上のセル行と列arがエコーバックされ、 x(、)配列から次の20列と次の50行をDataTableに追加しようとします。DataTableは、datagridviewに表示されているデータを更新します。しかし、これは動作しません。

1つの質問DataTableにユーザーが入力した配列全体を入力すると、datagridview1を設定して、たとえば50行と20列だけが表示範囲に追加されるようにすることができます。ユーザーが配列内のどこにいるかをスクロールしないで、アレイ全体をDataTableに入れると、このコードはうまく動作しますが、追加が必要な計算更新に続いて列を追加するときにDataTableを更新するのに時間がかかりますより多くのフィールドの換言すれば、例えばDataTableの1000行と50個のフィールドとx(、)に加えられた20個の列[つまり、Redim Preserve x(行、50 + 20)]を使用してDataTableを更新すると、既に1000の行と50の列がある場合、20の列をDataTableに追加します。

'In a global module: 
Public MainDataTable As New DataTable 
Public FieldType() As Byte ' Byte array to denote the type of field (object, double, long, string, etc.) 


Sub showdgv() 
    Dim x(1000, 100) As Object 
    Dim columnheaders(100) As String 
    Dim rowheaders(1000) As String 
    Dim fieldnames(100) As String 
    Dim rownames(1000) As String 

    For i as Integer = 0 To 999 
     For j As Integer = 0 to 99 
      x(i, j) = Rnd() 
     Next 
    Next 

    'Dynamically create a datagridview 
    Dim datagridview1 As New DataGridView 
    Me.Controls.Add(datagridview1) 
    datagridview1.AutoSize = True 
    datagridview1.AutoResizeRows() 
    datagridview1.AutoResizeColumns() 
    datagridview1.ClearSelection() 
    DoubleBufferedDGV(datagridview1, True) 
    datagridview1.AutoResizeRowHeadersWidth(DataGridViewRowHeadersWidthSizeMode.AutoSizeToAllHeaders) 
    Dim dgvColumnHeaderStyle As New DataGridViewCellStyle() 
    dgvColumnHeaderStyle.Alignment = DataGridViewContentAlignment.MiddleCenter 
    datagridview1.ColumnHeadersDefaultCellStyle = dgvColumnHeaderStyle 
    datagridview1.AllowUserToAddRows = False 
    datagridview1.ScrollBars = ScrollBars.Both 
    datagridview1.Refresh() 
    datagridview1.Dock = DockStyle.Fill 
    AddHandler datagridview1.Scroll, AddressOf Me.DGV1_Scroll 

    'Instantiate the class object to update the DGV by loading the DataTable with the contant of the array x(,) 
    Dim dgv As New DGVCREATE(datagridview1, x, columnheaders, rowheaders, FieldNames, RowNames) 

End Sub 


Public Class DGVCREATE 
    Dim x(,) As Object 
    Dim columnheaders() As String 
    Dim rowheaders() As String 
    Dim fieldnames() As String 
    Dim rownames() As String 
    Sub New(ByRef dgv As DataGridView, ByVal x(,) As Object, ByVal columnheaders() As String, ByVal rowheaders() As String, ByVal FieldNames() As String, ByVal RowNames() As String) 
     Dim main As Form1 = CType(Application.OpenForms(0), Form1) 
     dgv.RowHeadersWidthSizeMode = DataGridViewRowHeadersWidthSizeMode.DisableResizing 
     GetResultsTable(x, columnheaders, rowheaders, FieldNames, RowNames) 
     'new trial code 
     dgv.AutoGenerateColumns = True 
     'Application.DoEvents() 
     dgv.DataSource = main.MainDataTable 
     dgv.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill 
     For i As Integer = 0 To main.MainDataTable.Columns.Count - 1 
      Dim Column As New DataGridViewTextBoxColumn 
      Column.Name = main.MainDataTable.Columns(i).ColumnName 
      Column.DataPropertyName = main.MainDataTable.Columns(i).ColumnName 
      Column.HeaderText = main.MainDataTable.Columns(i).ColumnName 
      Column.FillWeight = 70 
      Column.MinimumWidth = 70 
      dgv.Columns.Add(Column) 
     Next i 
     dgv.AutoSize = True 
    End Sub 

    Public Sub GetResultsTable(ByVal x(,) As Object, ByVal columnheaders() As String, ByVal rowheaders() As String, ByVal fieldnames() As String, ByVal rownames() As String) 
     Dim main As Form1 = CType(Application.OpenForms(0), Form1) 
     main.MainDataTable.Clear() 
     main.MainDataTable.Rows.Clear() 
     main.MainDataTable.Columns.Clear() 

     ' Loop through all process names. 
     For j As Integer = dgvbegincol To dgvbegincol + 30 ' 0 To UBound(columnheaders) - 1 
      ' The current process name. 
      ' Add the program name to our columns. 
      Try 
       If FieldType(j + 1) = 0 Then main.MainDataTable.Columns.Add(fieldnames(j + 1), GetType(Object)) 
       If FieldType(j + 1) = 1 Then main.MainDataTable.Columns.Add(fieldnames(j + 1), GetType(Double)) 
       If FieldType(j + 1) = 2 Then main.MainDataTable.Columns.Add(fieldnames(j + 1), GetType(Long)) 
       If FieldType(j + 1) = 3 Then main.MainDataTable.Columns.Add(fieldnames(j + 1), GetType(Long)) 
       If FieldType(j + 1) = 4 Then main.MainDataTable.Columns.Add(fieldnames(j + 1), GetType(String)) 
      Catch ex As Exception 
       If InStr(ex.Message, "column name") > 0 Then 
        Try 
         If FieldType(j + 1) = 0 Then main.MainDataTable.Columns.Add(fieldnames(j + 1) & "_" & varsuffixvalue.ToString, GetType(Object)) 
         If FieldType(j + 1) = 1 Then main.MainDataTable.Columns.Add(fieldnames(j + 1) & "_" & varsuffixvalue.ToString, GetType(Double)) 
         If FieldType(j + 1) = 2 Then main.MainDataTable.Columns.Add(fieldnames(j + 1) & "_" & varsuffixvalue.ToString, GetType(Long)) 
         If FieldType(j + 1) = 3 Then main.MainDataTable.Columns.Add(fieldnames(j + 1) & "_" & varsuffixvalue.ToString, GetType(Long)) 
         If FieldType(j + 1) = 4 Then main.MainDataTable.Columns.Add(fieldnames(j + 1) & "_" & varsuffixvalue.ToString, GetType(String)) 
         fieldnames(j + 1) = fieldnames(j + 1) & "_" & varsuffixvalue.ToString 
        Catch ex1 As Exception 
         If InStr(ex1.Message, "column name") > 0 Then 
          varsuffixvalue += 1 
          If FieldType(j + 1) = 0 Then main.MainDataTable.Columns.Add(fieldnames(j + 1) & "_" & varsuffixvalue.ToString, GetType(Object)) 
          If FieldType(j + 1) = 1 Then main.MainDataTable.Columns.Add(fieldnames(j + 1) & "_" & varsuffixvalue.ToString, GetType(Double)) 
          If FieldType(j + 1) = 2 Then main.MainDataTable.Columns.Add(fieldnames(j + 1) & "_" & varsuffixvalue.ToString, GetType(Long)) 
          If FieldType(j + 1) = 3 Then main.MainDataTable.Columns.Add(fieldnames(j + 1) & "_" & varsuffixvalue.ToString, GetType(Long)) 
          If FieldType(j + 1) = 4 Then main.MainDataTable.Columns.Add(fieldnames(j + 1) & "_" & varsuffixvalue.ToString, GetType(String)) 
          fieldnames(j + 1) = fieldnames(j + 1) & "_" & varsuffixvalue.ToString 
         End If 
        End Try 
       End If 
      End Try 

      Do While main.MainDataTable.Rows.Count < UBound(rowheaders) 
       Dim myRow As DataRow 
       myRow = main.MainDataTable.NewRow() 
       main.MainDataTable.Rows.Add(myRow) 
      Loop 
      ' Add each item to the cells in the column. 
      For i As Integer = dgvbeginrow To dgvbeginrow + 50 ' 0 To UBound(rowheaders) - 1 
       main.MainDataTable.Rows(i)(j) = If(x(i, j), CObj(DBNull.Value)) 
      Next i 
     Next j 
     dgvThreadDone.Set() 
    End Sub 
End Class 

Sub DGV1_Scroll(sender As Object, e As ScrollEventArgs) 
    Dim x(,) As Object 
    Dim rowheaders() As String, columnheaders() As String 
    rowheaders = RowNames.Clone 
    columnheaders = FieldNames.Clone 

    For Each c In Me.Controls 
     If TypeOf (c) Is DataGridView Then 
      'Public dgvbeginrow, dgvendrow, dgvbegincol, dgvendcol As Integer 
      dgvbeginrow = c.FirstDisplayedCell.RowIndex 
      dgvbegincol = c.FirstDisplayedCell.ColumnIndex 

      Dim dgv As New DGVCREATE(c, x, columnheaders, rowheaders, FieldNames, RowNames) 

     End If 
    Next 
End Sub 
+0

私はあなたが 'DataTable'とあなたの2次元配列を交換をお勧めします。 – SSS

答えて

1

は、私はあなたが移入するためDataTableを使用してより良い結果を得るだろうと思い、あなたのDataGridView

Public Class Form1 
    'For this example, add a DataGridView and Button under it 
    Sub New() 

    ' This call is required by the designer. 
    InitializeComponent() 

    ' Add any initialization after the InitializeComponent() call. 
    Dim dtb As New DataTable() 
    'Start with 50 columns and 1000 rows 
    For intCol As Integer = 0 To 49 
     dtb.Columns.Add("Col" & intCol.ToString("000")) 
    Next intCol 
    For intRow As Integer = 0 To 999 
     Dim drw As DataRow = dtb.NewRow 
     For intCol As Integer = 0 To 49 
     drw(intCol) = Rnd() 
     Next intCol 
     dtb.Rows.Add(drw) 
    Next intRow 
    DataGridView1.DataSource = dtb 
    DataGridView1.Anchor = AnchorStyles.Top Or AnchorStyles.Left Or AnchorStyles.Right Or AnchorStyles.Bottom 
    Button1.Anchor = AnchorStyles.Left Or AnchorStyles.Bottom 
    End Sub 

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click 
    'Add 20 columns 
    Me.Cursor = Cursors.WaitCursor 
    Dim dtb As DataTable = DirectCast(DataGridView1.DataSource, DataTable) 
    Dim intOldColumnCount As Integer = dtb.Columns.Count 
    For intCol As Integer = intOldColumnCount To intOldColumnCount + 20 
     dtb.Columns.Add("Col" & intCol.ToString("000")) 
    Next intCol 
    For intRow As Integer = 0 To dtb.Rows.Count - 1 
     Dim drw As DataRow = dtb.Rows(intRow) 
     For intCol As Integer = intOldColumnCount To intOldColumnCount + 20 
     drw(intCol) = Rnd() 
     Next intCol 
    Next intRow 
    Me.Cursor = Cursors.Default 
    End Sub 
End Class 
+0

ありがとう、私はコードの例を試してみましょう!配列を最初に更新して(非常に速く)、DataTableを書き込むと、すでにここでは実行されていません: 'main.MainDataTable.Rows(i)(j)= If(x(i、j) 、CObj(DBNull.Value)) '?私はこれがとても遅いと思います。データテーブル全体が更新された配列で満たされ、datagridviewがロードされた後、データグリッドビュー全体をすばやく移動できます。ただし、DataTableをリセットするのは時間がかかりすぎるようです(?) – wrtsvkrfm

+0

また、コード例では、DataTableにコピーする必要がある乱数の配列を持っているのに対し、DataTableには乱数を埋めます。配列は数学にとって非常に高速であるため、DataTableのセルで数学を行うのは意味がありません(?)これは、「数学に2Dの二重とオブジェクト配列を使用しないようにする」(?)提案。 – wrtsvkrfm

+0

'DataGridViewTextBoxColumn'を追加するループの各反復で、dgvが再描画される可能性があります。 '.AutoGenerateColumns = False'を設定し、' .DataSource'を設定する前に 'DataGridViewTextBoxColumn'を設定することができます。私は 'DataGridView.SuspendLayout'を使って再描画を抑制することがないので、' DataSource'の設定をできるだけ遅らせるようにしました。 – SSS

関連する問題