- [VB.NET] Hướng dẫn giải captcha sử dụng dịch vụ AZCaptcha API trên winform
- [C#] Hướng dẫn chứng thực đăng nhập ứng dụng bằng vân tay (Finger Print) trên máy tính
- [C#] Color Thief cách xuất màu sắc thiết kế từ hình ảnh
- [C#] Cách tạo bản quyền và cho phép dùng thử ứng dụng Winform
- [C#] Hướng dẫn sử dụng trình duyệt web Chrome convert HTML sang tập tin file PDF
- [C#] Kết nôi điện thoại Android, IOS với App Winform via Bluetooth
- [DATABASE] Cách query cộng trừ dồn dần trong Sqlserver
- [C#] Thiết kế ứng dụng Console đẹp với thư viện Spectre.Console
- [C#] Thiết kế ứng dụng Single Instance và đưa ứng dụng lên trước nếu kiểm tra ứng dụng đang chạy
- [C#] Giới thiệu JSON Web Token và cách đọc chuỗi token
- [C#] Cách tăng giảm font chữ tất cả các control trên winform
- [DEVEXPRESS] Tích hợp chức năng Tìm kiếm Search vào CheckedComboboxEdit
- [C#] Gởi email Metting Calendar Reminder kèm nhắc thời gian lịch họp
- [C#] Tìm kiếm xem danh sách từ khóa có tồn tại trong đoạn văn bản hay không
- [C#] Thiết kế giao diện ứng dụng trên Console sử dụng thư viện Terminal.Gui
- [C#] Hướng dẫn tạo mã VietQR Payment API Winform
- [C#] Sử dụng thư viện BenchmarkDotNet đo hiệu năng của hảm Method
- [DEVEXPRESS] Tìm kiếm không dấu tô màu highlight có dấu trên C# Winform
- [C#] Chia sẻ source code tạo hiệu ứng pixel Image trên winform
- [C#] Hướng dẫn kiểm tra số Container hợp lệ hay không
[VB.NET] Hướng dẫn cuộn chuột load image vào Grid View từ URL bất đồng bộ (Async load image to gridview big data)
Bài viết hôm nay, mình sẽ hướng dẫn các bạn load hình ảnh từ đường dẫn trong thư mục ổ đĩa của bạn vào Column của GridView Devexpress.
[VB.NET] SCROLL MOUSE LOAD IMAGE FROM URL TO IMAGE GRIDVIEW ASYNC DEVEXPRESS
Hôm trước, mình cũng đã có viết bài hướng dẫn cho các bạn tải hình ảnh từ url vào gridview devexpress bằng VB.NET. Tuy nhiên, khi các bạn tải dữ liệu ít vào gridview thì không sao.
Nếu dữ liệu của các bạn là dữ liệu lớn (big data) khoảng 1000 record trở lên, thì khi các bạn kéo chuột trong gridview thì sẽ có cảm giác bị lag.
Vì vậy, bài toán đặt ra là chúng ta sẽ làm thế nào cho load dữ liệu không bị lag.
+ Load dữ liệu khi rê chuột, tức là kéo chuột đến đâu sẽ tải dữ liệu đến đó giống như các bạn load hình ảnh theo Ajax trên website vậy.
+ Mình sẽ tải hình ảnh bất đồng bộ để tối ưu hóa tối độ tải trên gridview.
+ Khi kéo chuột đến record nào trên gridview hiển thị sẽ ưu tiên cho hiển thị hình ảnh ở vị trí đó.
Dưới đây là giao diện của demo của chương trình:
+ Viết hàm tạo dữ liệu demo sử dụng for để tạo datatable trong bài mình ví dụ là tạo ra 100.000 record.
Private Function FillDataTable() As DataTable
Dim _dataTable As New DataTable()
Dim col As DataColumn
Dim row As DataRow
_dataTable.TableName = "SomeTable"
col = New DataColumn()
col.ColumnName = "Display Image"
col.DataType = System.Type.[GetType]("System.String")
_dataTable.Columns.Add(col)
Dim j = 0
For i = 1 To 100000
j = j + 1
row = _dataTable.NewRow()
row("Display Image") = "photoimg" & j.ToString & ".jpg"
_dataTable.Rows.Add(row)
If (j = 13) Then
j = 0
End If
Next
Return _dataTable
End Function
+ Tiếp tục cần tạo Module với tên sau: mld_LoadAsyncImage.vb
Source code
Imports System.IO
Imports System.Threading
Imports System.Threading.Tasks
Imports DevExpress.XtraGrid
Imports DevExpress.XtraGrid.Views.Base
Imports DevExpress.XtraGrid.Views.Grid
Module mld_LoadAsyncImage
Private imageArr() As Image
Private Const THUMBNAIL_IMG_HEIGHT As Integer = 80
Private cancelTaskSourceGridView As CancellationTokenSource = New CancellationTokenSource()
Private listCancelTaskSourceVisibleRow As List(Of CancellationTokenSource) = New List(Of CancellationTokenSource)
Private myView As GridView
Public Sub GridControl_DataSourceChanged(sender As Object, e As EventArgs)
Dim gc = TryCast(sender, GridControl)
myView = TryCast(gc.FocusedView, GridView)
Dim dt = TryCast(gc.DataSource, DataTable)
cancelTaskSourceGridView.Cancel()
DisposeImageArr()
If dt IsNot Nothing Then
imageArr = New Image(dt.Rows.Count - 1) {}
cancelTaskSourceGridView = New CancellationTokenSource
Task.Factory.StartNew(Sub()
AsyncLoadImage(cancelTaskSourceGridView)
End Sub, cancelTaskSourceGridView)
End If
End Sub
Private Sub AsyncLoadImage(cancelSource As CancellationTokenSource)
Dim dt = TryCast(myView.GridControl.DataSource, DataTable)
Dim imgArr = imageArr
For r = 0 To dt.Rows.Count - 1 Step 1
If Not cancelSource.Token.IsCancellationRequested Then
'Load hình từ file
Dim filename As String = dt.Rows(r)("Display Image")
Dim img As Image
If File.Exists(filename) Then
Using imgStream = New FileStream(filename, FileMode.Open, FileAccess.Read)
img = ResizeImage(Image.FromStream(imgStream), THUMBNAIL_IMG_HEIGHT)
imgStream.Close()
End Using
Else
img = ResizeImage(My.Resources.logo, THUMBNAIL_IMG_HEIGHT, False)
End If
imgArr(r) = img
'load hình từ ftp server
''ftp://192.168.0.96/green_human.jpg
'Dim request = WebRequest.Create("ftp://192.168.0.96/green_human.jpg")
'Dim response = request.GetResponse()
'Dim Stream = response.GetResponseStream()
'Dim bmp = Bitmap.FromStream(Stream)
Else
'MsgBox("task cancel")
Exit For
End If
Next
End Sub
Public Sub BandedGridView1_CustomDrawCell(sender As Object, e As RowCellCustomDrawEventArgs)
If e.Column.FieldName = "Display Image" Then
If imageArr IsNot Nothing Then
Dim rowSourceIndex = myView.GetDataSourceRowIndex(e.RowHandle)
If rowSourceIndex > -1 AndAlso imageArr(rowSourceIndex) IsNot Nothing Then
Dim sourceImg = imageArr(rowSourceIndex)
Dim rect = e.Bounds
Dim hs = Math.Min(rect.Width / sourceImg.Width, rect.Height / sourceImg.Height)
rect.Width = Convert.ToInt32(sourceImg.Width * hs)
rect.Height = Convert.ToInt32(sourceImg.Height * hs)
rect.X = rect.X + Convert.ToInt32((e.Bounds.Width - rect.Width) / 2)
rect.Y = rect.Y + Convert.ToInt32((e.Bounds.Height - rect.Height) / 2)
e.Graphics.DrawImage(sourceImg, rect)
Else
Dim cancelSource = New CancellationTokenSource
SyncLock listCancelTaskSourceVisibleRow
listCancelTaskSourceVisibleRow.Add(cancelSource)
If listCancelTaskSourceVisibleRow.Count > 20 Then
listCancelTaskSourceVisibleRow(0).Cancel()
listCancelTaskSourceVisibleRow.RemoveAt(0)
End If
End SyncLock
Task.Factory.StartNew(
Sub()
AsyncLoadImageDrawCell(e, cancelSource)
End Sub, cancelSource)
End If
End If
e.Handled = True
End If
End Sub
Private Sub AsyncLoadImageDrawCell(e As RowCellCustomDrawEventArgs, cancelSource As CancellationTokenSource)
If Not cancelSource.Token.IsCancellationRequested Then
Dim rowSourceIndex = myView.GetDataSourceRowIndex(e.RowHandle)
Dim img As Image
If File.Exists(e.CellValue) Then
img = ResizeImage(Image.FromFile(e.CellValue), THUMBNAIL_IMG_HEIGHT)
Else
img = ResizeImage(My.Resources.logo, THUMBNAIL_IMG_HEIGHT, False)
End If
imageArr(rowSourceIndex) = img
'trigger CustomDrawCell reload khi đã có Img
myView.GridControl.BeginInvoke(
Sub()
myView.SetRowCellValue(e.RowHandle, "Display Image", myView.GetRowCellValue(e.RowHandle, "Display Image"))
End Sub)
End If
End Sub
Private Sub DisposeImageArr()
If imageArr IsNot Nothing Then
For r = 0 To imageArr.Length - 1 Step 1
If imageArr(r) IsNot Nothing Then
imageArr(r).Dispose()
End If
Next
imageArr = Nothing
End If
End Sub
Public Function ResizeImage(b As Image, width As Integer, height As Integer, Optional ByVal disposeOriginal As Boolean = True) As Image
Dim result As Image = New Bitmap(width, height)
Using g = Graphics.FromImage(result)
g.DrawImage(b, 0, 0, width, height)
If disposeOriginal Then
b.Dispose()
b = Nothing
End If
End Using
Return result
End Function
Public Function ResizeImage(b As Image, height As Integer, Optional ByVal disposeOriginal As Boolean = True) As Image
Dim width = Convert.ToInt32(height / b.Height * b.Width)
Return ResizeImage(b, width, height, disposeOriginal)
End Function
End Module
+ Tiếp theo mình sẽ viết sự kiện cho Datasource_Change
Private Sub SimpleButton1_Click(sender As Object, e As EventArgs) Handles SimpleButton1.Click
AddHandler GridControl1.DataSourceChanged, AddressOf mld_LoadAsyncImage.GridControl_DataSourceChanged
AddHandler GridView1.CustomDrawCell, AddressOf mld_LoadAsyncImage.BandedGridView1_CustomDrawCell
Dim dt As DataTable = FillDataTable()
GridControl1.DataSource = dt
End Sub
VIDEO DEMO ỨNG DỤNG
HAVE FUN :)