2010-06-15 34 views
9

Tôi gặp sự cố với ứng dụng Windows Forms.Có gì sai với lời gọi qua chủ đề của tôi trong Windows Forms?

Biểu mẫu phải được hiển thị từ một chuỗi khác. Vì vậy, trong các lớp mẫu, tôi có đoạn mã sau:

private delegate void DisplayDialogCallback(); 

public void DisplayDialog() 
{ 
    if (this.InvokeRequired) 
    { 
     this.Invoke(new DisplayDialogCallback(DisplayDialog)); 
    } 
    else 
    { 
     this.ShowDialog(); 
    } 
} 

Bây giờ, mỗi khi tôi chạy này, một InvalidOperationException được ném trên dòng this.ShowDialog();:

"Cross-chủ đề hoạt động không hợp lệ: Kiểm soát 'SampleForm' được truy cập từ một chuỗi khác với chuỗi được tạo trên đó. "

Có gì sai với đoạn mã này? Nó không phải là một cách hợp lệ để thực hiện cuộc gọi chéo? Có điều gì đặc biệt với ShowDialog() không?

+3

Ra khỏi tò mò, những gì hiện IsHandleCreated chương trình? –

+0

@Marc Gravell: IsHandleCreated là sai. Vì vậy, một cách tự nhiên, như nhiều người đã nói, mã đang thực hiện trước khi biểu mẫu được hiển thị. –

Trả lời

4

Hãy thử điều này một:

private delegate void DisplayDialogCallback(); 

public void DisplayDialog() 
{ 
    if (this.InvokeRequired) 
    { 
     this.Invoke(new DisplayDialogCallback(DisplayDialog)); 
    } 
    else 
    { 
     if (this.Handle != (IntPtr)0) // you can also use: this.IsHandleCreated 
     { 
      this.ShowDialog(); 

      if (this.CanFocus) 
      { 
       this.Focus(); 
      } 
     } 
     else 
     { 
      // Handle the error 
     } 
    } 
} 

Xin lưu ý rằng InvokeRequired lợi nhuận

đúng nếu Xử lý của kiểm soát được tạo trên một chủ đề khác với chủ đề gọi số (indi nói rằng bạn phải thực hiện cuộc gọi đến kiểm soát thông qua một phương thức gọi); ngược lại, sai.

và do đó, nếu kiểm soát chưa được tạo, giá trị trả về sẽ là false!

8

Có thể bạn đang thực thi mã này trước khi biểu mẫu được hiển thị.
Do đó, InvokeRequired đang trả lại false.

5

Tôi tin rằng những gì đang xảy ra ở đây là mã này đang được chạy trước khi Form được hiển thị.

Khi một Form được tạo trong. Net, nó không ngay lập tức đạt được ái lực cho một chuỗi cụ thể. Chỉ khi các hoạt động nhất định được thực hiện như hiển thị nó hoặc nắm lấy tay cầm thì nó có được ái lực không. Trước khi điều đó xảy ra, thật khó cho InvokeRequired hoạt động chính xác.

Trong trường hợp cụ thể này, không có mối quan hệ nào được thiết lập và không có kiểm soát cha mẹ tồn tại để InvokeRequired trả về false vì nó không thể xác định chuỗi ban đầu.

Cách khắc phục điều này là thiết lập mối quan hệ cho kiểm soát của bạn khi được tạo trên chuỗi giao diện người dùng. Cách tốt nhất để làm điều này là chỉ cần hỏi điều khiển cho thuộc tính xử lý của nó.

var notUsed = control.Handle; 
+0

Lạ, nhưng nhận được 'control.Handle' không thay đổi bất cứ điều gì: ngoại lệ vẫn bị ném. Thay vào đó, đề nghị Lorenzo hoạt động tốt. IMHO, điều này là do thực tế là trình biên dịch chỉ cần loại bỏ 'var notUsed = control.Handle;' dòng, trong khi 'notUsed' biến là ... không được sử dụng. –

0

Bạn luôn có thể thử kiểm tra đối với một điều khiển khác.

Ví dụ, bạn có thể truy cập vào bộ sưu tập Application.Forms

public Control GetControlToInvokeAgainst() 
{ 
    if(Application.Forms.Count > 0) 
    { 
     return Application.Forms[0]; 
    } 
    return null; 
} 

Sau đó, trong phương pháp DisplayDialog() của bạn, hãy gọi GetControlToInvokeAgainst() và kiểm tra cho null trước khi cố gắng thực hiện một cuộc gọi InvokeRequired.

0

Rất có thể tay cầm của điều khiển chưa được tạo, trong trường hợp này Control.InvokeRequired trả về false.

Kiểm tra thuộc tính Control.IsHandleCreated để xem đây có phải là trường hợp không.

0

Tôi cũng nghĩ rằng SLaks là chính xác. Từ msdn (http://msdn.microsoft.com/en-us/library/system.windows.forms.control.invokerequired.aspx):

Nếu không tìm thấy xử lý thích hợp, phương thức InvokeRequired trả về sai.

Nếu có thể trong trường hợp của bạn, tôi sẽ cố gắng kết hợp việc tạo và hiển thị kiểm soát theo một phương pháp duy nhất, tức là:

public DisplayDialog static Show() 
{ 
    var result = new DisplayDialog; //possibly cache instance of the dialog if needed, but this could be tricky 
    result.ShowDialog(); 
    return result; 
} 

bạn có thể gọi Show từ một thread khác nhau

1

Bạn có khả năng nhận được mã này trước khi biểu mẫu được hiển thị và do đó, xử lý cửa sổ chưa được tạo.

Bạn có thể thêm mã này trước khi mã của bạn và tất cả nên được tốt:

if (! this.IsHandleCreated) 
    this.CreateHandle(); 

Edit: Có một vấn đề với mã của bạn. Khi biểu mẫu được hiển thị, bạn không thể gọi lại ShowDialog(). Bạn sẽ nhận được một ngoại lệ hoạt động không hợp lệ. Bạn có thể muốn sửa đổi phương pháp này khi phương pháp khác đã đề xuất.

Bạn có thể phục vụ tốt hơn gọi ShowDialog() trực tiếp từ lớp gọi điện thoại và có phương pháp khác cho BringToFront() hoặc một cái gì đó như thế ...

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