2008-08-27 36 views
28

Trong một dự án WinForms VB.NET tôi nhận được một ngoại lệKhông thể truy cập đối tượng được xử lý - Cách khắc phục?

Không thể truy cập một đối tượng xử lý

khi đóng một biểu mẫu. Nó xảy ra rất hiếm khi và tôi không thể tái tạo nó theo yêu cầu. Theo dõi ngăn xếp trông giống như sau:

Cannot access a disposed object. Object name: 'dbiSchedule'. 
    at System.Windows.Forms.Control.CreateHandle() 
    at System.Windows.Forms.Control.get_Handle() 
    at System.Windows.Forms.Control.PointToScreen(Point p) 
    at Dbi.WinControl.Schedule.dbiSchedule.a(Boolean A_0) 
    at Dbi.WinControl.Schedule.dbiSchedule.a(Object A_0, EventArgs A_1) 
    at System.Windows.Forms.Timer.OnTick(EventArgs e) 
    at System.Windows.Forms.Timer.TimerNativeWindow.WndProc(Message& m) 
    at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) 

DbiSchedule là điều khiển lịch từ công nghệ Dbi. Có một bộ đếm thời gian trên biểu mẫu cập nhật lịch biểu trên màn hình vài phút một lần.

Bất kỳ ý tưởng nào gây ra ngoại lệ và cách tôi có thể khắc phục sự cố đó? hoặc thậm chí chỉ có thể tạo lại nó theo yêu cầu?


Hej! Cảm ơn tất cả các câu trả lời. Chúng tôi ngừng Timer trên sự kiện FormClosing và chúng tôi kiểm tra các tài sản IsDisposed trên thành phần lịch trình trước khi sử dụng nó trong sự kiện Timer Tick nhưng nó không giúp đỡ.

Đó là một vấn đề thực sự gây phiền nhiễu vì nếu ai đó đã đưa ra giải pháp đã hoạt động - tôi sẽ không thể xác nhận giải pháp vì tôi không thể tạo lại sự cố theo cách thủ công.

Trả lời

19

Hãy thử kiểm tra thuộc tính IsDisposed trước khi truy cập điều khiển. Bạn cũng có thể kiểm tra nó trên sự kiện FormClosing, giả sử bạn đang sử dụng sự kiện FormClosed.

Chúng tôi dừng Timer trên các sự kiện FormClosing và chúng tôi kiểm tra tài sản trên các thành phần lịch IsDisposed trước khi sử dụng nó trong Timer sự kiện Tick nhưng nó không giúp đỡ.

Gọi GC.Collect trước khi kiểm tra IsDisposed có thể hữu ích, nhưng hãy cẩn thận với điều này. Đọc bài viết này của Rico Mariani "When to call GC.Collect()".

1

Bạn chắc chắn bộ hẹn giờ không còn tồn tại 'dbiSchedule' bằng cách nào đó và kích hoạt sau khi 'dbiSchedule' đã được xử lý?

Nếu đó là trường hợp bạn có thể tạo lại liên tục hơn nếu hẹn giờ kích hoạt nhanh hơn, do đó làm tăng cơ hội bạn đóng Biểu mẫu ngay khi bộ hẹn giờ đang kích hoạt.

0

Nhìn vào dấu vết ngăn lỗi, có vẻ như bộ hẹn giờ của bạn vẫn hoạt động. Hãy thử hủy hẹn giờ khi đóng biểu mẫu (tức là trong phương thức OnClose() của biểu mẫu). Điều này trông giống như giải pháp sạch nhất.

10

Dường như vấn đề về luồng.
Giả thuyết: Có thể bạn có một chuỗi chính và một chuỗi hẹn giờ truy cập vào điều khiển này. Các chủ đề chính tắt - gọi Control.Dispose() để chỉ ra rằng tôi đang thực hiện với điều khiển này và tôi sẽ làm cho không có nhiều cuộc gọi đến này. Tuy nhiên, bộ đếm thời gian vẫn hoạt động - một chuyển đổi ngữ cảnh cho chủ đề đó, nơi nó có thể gọi các phương thức trên cùng một điều khiển. Bây giờ kiểm soát nói rằng tôi đang xử lý (đã từ bỏ nguồn lực của tôi) và tôi sẽ không làm việc nữa. Ngoại lệ ObjectDisposed.

Làm thế nào để giải quyết việc này: Trong thread hẹn giờ, trước khi gọi phương pháp/tài sản trên sự kiểm soát, làm một tấm séc với

if ControlObject.IsDisposed then return; // or do whatever - but don't call control methods 

HOẶC dừng thread timer TRƯỚC xử lý đối tượng.

+11

Kiểm tra IsDisposed sẽ giảm, nhưng không loại bỏ được sự cố. Giải pháp đúng là dừng hẹn giờ trước khi đóng biểu mẫu. –

1

Một địa điểm khác bạn có thể dừng hẹn giờ là sự kiện FormClosing - điều này xảy ra trước khi biểu mẫu thực sự bị đóng, do đó là nơi tốt để dừng mọi thứ trước khi chúng có thể truy cập tài nguyên không có sẵn.

2

chúng tôi kiểm tra tài sản IsDisposed trên thành phần lịch trình trước khi sử dụng nó trong trường hợp Timer Tick nhưng nó không giúp đỡ.

Nếu tôi hiểu rằng theo dõi ngăn xếp, nó không phải là bộ đếm thời gian của bạn là vấn đề, nó là một trong kiểm soát chính nó - nó có thể là họ không làm sạch đúng cách.

Bạn có đang gọi rõ ràng Vứt bỏ trên kiểm soát của họ không?

2

Dừng bộ hẹn giờ không có nghĩa là nó sẽ không được gọi lại, tùy thuộc vào thời điểm bạn ngừng bộ hẹn giờ, timer_tick vẫn có thể được xếp hàng đợi trên vòng lặp tin nhắn cho biểu mẫu. Điều gì sẽ xảy ra là bạn sẽ nhận được thêm một dấu tích mà bạn có thể không mong đợi. Những gì bạn có thể làm là trong timer_tick của mình, hãy kiểm tra thuộc tính Đã bật của bộ hẹn giờ trước khi thực hiện phương thức Timer_Tick.

1

Nếu điều này xảy ra không thường xuyên thì phỏng đoán của tôi là nó có liên quan đến bộ hẹn giờ.

Tôi đoán (và đây chỉ là phỏng đoán vì tôi không có quyền truy cập vào mã của bạn) mà bộ hẹn giờ đang kích hoạt trong khi biểu mẫu đang bị đóng. Các đối tượng dbiSchedule đã được xử lý nhưng bộ đếm thời gian bằng cách nào đó vẫn quản lý để cố gắng gọi nó. Điều này không nên xảy ra, bởi vì nếu bộ đếm thời gian có một tham chiếu đến đối tượng lịch trình thì bộ thu gom rác sẽ thấy điều này và không vứt bỏ nó.

Điều này dẫn tôi hỏi: bạn có đang gọi Dispose() trên đối tượng lịch biểu theo cách thủ công không? Nếu vậy, bạn đang làm điều đó trước khi xử lý của bộ đếm thời gian? Hãy chắc chắn rằng bạn giải phóng tất cả các tham chiếu đến đối tượng lịch biểu trước khi vứt bỏ nó (tức là bỏ hẹn giờ trước).

Bây giờ tôi nhận ra rằng một vài tháng đã trôi qua giữa thời gian bạn đăng bài này và khi tôi trả lời, vì vậy hy vọng bạn đã giải quyết vấn đề này. Tôi đang viết điều này vì lợi ích của những người khác có thể đến sau với một vấn đề tương tự.

Hy vọng điều này sẽ hữu ích.

2

Tôi đã gặp sự cố tương tự và đã giải quyết vấn đề bằng cờ boolean được đặt khi biểu mẫu đóng (System.Timers.Timer không có thuộc tính IsDisposed). Ở khắp mọi nơi trên biểu mẫu tôi đã bắt đầu hẹn giờ, tôi đã kiểm tra cờ này. Nếu nó đã được thiết lập, sau đó không bắt đầu hẹn giờ. Dưới đây là lý do:

lý do:

tôi đã dừng lại và xử lý các bộ đếm thời gian trong trường hợp hình thức bế mạc. Tôi đã bắt đầu hẹn giờ trong sự kiện Timer_Elapsed(). Nếu tôi đã đóng biểu mẫu ở giữa sự kiện Timer_Elapsed(), bộ đếm thời gian sẽ ngay lập tức bị xử lý bởi sự kiện Form_Closing().Điều này sẽ xảy ra trước khi sự kiện Timer_Elapsed() sẽ kết thúc và quan trọng hơn, trước khi nó đã đến dòng mã này:

_timer.Start() 

Ngay sau khi dòng đó được thực hiện một ObjectDisposedException() sẽ được ném với lỗi mà bạn đề cập .

Giải pháp:

Private Sub myForm_FormClosing(ByVal sender As System.Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles MyBase.FormClosing 
    ' set the form closing flag so the timer doesn't fire even after the form is closed. 
    _formIsClosing = True 
    _timer.Stop() 
    _timer.Dispose() 
End Sub 

Dưới đây là bộ đếm thời gian trôi qua sự kiện:

Private Sub Timer_Elapsed(ByVal sender As System.Object, ByVal e As System.Timers.ElapsedEventArgs) Handles _timer.Elapsed 
    ' Don't want the timer stepping on itself (ie. the time interval elapses before the first call is done processing) 
    _timer.Stop() 

    ' do work here 

    ' Only start the timer if the form is open. Without this check, the timer will run even if the form is closed. 
    If Not _formIsClosing Then 
     _timer.Interval = _refreshInterval 
     _timer.Start() ' ObjectDisposedException() is thrown here unless you check the _formIsClosing flag. 
    End If 
End Sub 

điều Thú vị biết, mặc dù nó sẽ ném ObjectDisposedException khi cố gắng bắt đầu hẹn giờ, bộ đếm thời gian vẫn sẽ bắt đầu làm cho nó chạy ngay cả khi biểu mẫu đã bị đóng (luồng sẽ chỉ dừng lại khi ứng dụng đã đóng).

0

Giải pháp của tôi là để đặt một catch, & đang làm việc tốt

try {
this.Invoke (EventHandler mới (DoUpdate)); }
bắt {}

Các vấn đề liên quan