Cross-thread operation not valid

Các bài viết hướng dẫn về Visual Basic .NET và C#

Moderators: tungcan5diop, QUANITGROBEST

Post Reply
User avatar
Kỳ Nam
Guru
Guru
Posts: 510
Joined: Sun 12/08/2007 8:47 pm
Location: Qui Nhơn
Been thanked: 1 time
Contact:

Cross-thread operation not valid

Post by Kỳ Nam »

Tên bài viết: Cross-thread operation not valid
Tác giả: Kỳ Nam
Cấp độ bài viết: Nâng cao
Tóm tắt: Đây là 1 warning ( 0 phải là lỗi ) của VS khi Debug ( nếu chạy bình thường 0 phải debug thì sẽ 0 gặp ) , nó là warning vì thỉnh thoảng nó có thể gây ra lỗi
Nguyên nhân :

warning này sẽ xảy ra khi bạn chạy 1 method trên 1 control từ 1 thread 0 phải là thread mà control được tạo

cụ tỉ như dầy :
- bạn tạo 1 control C trên thread A
- bạn tạo 1 thread B
- trong thread B bạn chạy 1 method của C , chẳng hạn như gọi C.Text = "" , -> warning

warning chỉ xảy ra với những method mà có sử dụng đến handle của control C , chẳng hạn như Show , Hide , set_Text ( là thủ tục Set() của property Text ) , set_Size , ...

Handle của control là gì :

Nếu bạn dùng .NET mà trước kia chưa dùng Win32 và sau này cũng 0 đụng gì tới Win32 ( tức là 100% .NET đó , được dẩy thì rất quý :-D ) , bạn sẽ 0 biết về handle của control . Đại khái nó là địa chỉ của 1 window trong bộ nhớ . Class System.Windows.Forms.Control là 1 wrapper cho Window trong Win32

Khi bạn gọi thủ tục như Control.Show , nó sẽ gọi các hàm của Win32 , như là hàm ShowWindow([Handle của Window mà class Control đang wrap ] , [... 1 vài tham số khác])

Thấy là thủ tục Control.Show() sẽ dùng đến handle của control

"thread mà control được tạo" là gì :

Dim C as new Control -> đây 0 phải là lúc "control được tạo" hay đầy đủ là "handle của control chưa được tạo"

1 control bắt đầu có handle khi nó gọi hàm Win32 CreateWindow hoặc CreateWindowEx

Nó gọi hàm đó lúc nào , chỉ người viết ra class System.Windows.Forms.Control mới biết , hoặc bạn có thể đọc code của nó dùng .NET Reflector

Và "thread mà control được tạo" chính là thread mà class Control gọi hàm Win32 CreateWindow

cách bỏ qua warning
Đây là warning cho nên bạn có thể bỏ qua nó , như mọi warning khác . Bạn chỉ cần gọi thủ tục đây :
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = False

cách giải quyết warning

Bạn cần gọi các thủ tục "mà có dùng đến handle của control" trên "thread mà control được tạo"

VD đoạn code mà sẽ gây ra warning :

Code: Select all

Public Class Form1     Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click        'Tạo 1 thread mà sẽ dùng tới handle của Form1        Dim T As New Threading.Thread(AddressOf CrossThreadOperation)        T.Start()    End Sub     Private Sub CrossThreadOperation()        'Thủ tục CrossThreadOperation có dùng tới handle của Form1        Me.Text = Date.Now.ToString 'Warning ở đây    End Sub End Class
Khi click dô form , warning sẽ xảy ra , để ý là bạn phải chạy Debug thì mới thấy warning

Class Control có các method mà cho phép chạy 1 method trên thread của Control , đó là Invoke ( đồng bộ ) , BeginInvoke + EndInvoke ( 0 đồng bộ )

Để dùng các method đó , bạn cung cấp cho nó 1 delegate tới method mà bạn muốn chạy .

Code: Select all

Public Class Form1     Private Sub Form1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Click        'Tạo 1 thread mà sẽ dùng tới handle của Form1        Dim T As New Threading.Thread(AddressOf CrossThreadOperation)        T.Start()    End Sub     Private Sub CrossThreadOperation()        'Tạo delegate        Dim MI As New MethodInvoker(AddressOf SetText)        'Chạy delegate MI trên thread của Form1        Me.Invoke(MI)    End Sub     Private Sub SetText()        Me.Text = Date.Now.ToString    End Sub End Class
Khuyến mãi : Control.Invoke nó làm cái gì

Control.Invoke(delegate) sẽ send 1 message đến "Window mà Control đang wrap" , dùng hàm Win32 SendMessage , message đó sẽ chứa delegate

Window nhận message trên thread của nó , qua hàm WndProc ( hàm này được windows gọi chớ 0 phải window gọi , :-D windows là hệ điều hành ) , message nằm trong tham số của WndProc

Khi "Window mà Control đang wrap" nhận được message qua hàm WndProc , Control ( có toàn quyền xử lý hàm WndProc , WndProc chính là hàm mà class Control pass dô hàm CreateWindow ) sẽ chạy delegate đi kèm trong message , delegate đó sẽ được chạy trên thread của Window

Chấm hết , hi vọng bạn 0 lẫn lộn giữa Control , Window , Instance của Control :-D
Post Reply

Return to “[.NET] Bài viết hướng dẫn”