2008-09-18 44 views
12

Tôi đã tự bảo vệ mình thành một góc ở đây.Thừa kế các trình xử lý sự kiện trong C#

Tôi có một loạt các UserControl kế thừa từ một phụ huynh, trong đó có một vài phương pháp và sự kiện để đơn giản hóa mọi thứ vì vậy tôi không phải viết dòng và dòng mã gần giống. Như cách bạn làm. Phụ huynh không chứa các điều khiển khác. Những gì tôi muốn làm là chỉ có một trình xử lý sự kiện, trong UserControl cha mẹ, mà đi và làm những thứ mà chỉ kiểm soát cha mẹ mới có thể thực hiện (có nghĩa là, điều kiện gọi một sự kiện, như sự kiện được xác định trong phụ huynh). . Sau đó, tôi sẽ kết nối trình xử lý sự kiện này cho tất cả các hộp nhập của tôi trong các điều khiển con của tôi và các điều khiển con sẽ phân loại nhiệm vụ phân tích đầu vào và báo cho cha mẹ kiểm soát xem có nên ném sự kiện đó hay không. Đẹp và sạch sẽ, không lặp lại, mã sao chép-dán (mà cho tôi luôn luôn kết quả trong một lỗi).

Đây là câu hỏi của tôi. Visual Studio nghĩ rằng tôi quá thông minh một nửa, và cảnh báo tôi rằng "phương pháp 'CheckReadiness' [xử lý sự kiện trong phụ huynh] không thể là phương thức cho một sự kiện vì lớp này xuất phát từ đã định nghĩa phương thức." Có, Visual Studio, là điểm. Tôi muốn để có trình xử lý sự kiện chỉ xử lý các sự kiện được các lớp con ném và công việc duy nhất của nó là cho phép tôi kết nối các trẻ em mà không cần phải viết một dòng mã. Tôi không cần những trình xử lý bổ sung đó - tất cả các chức năng tôi cần được gọi tự nhiên khi trẻ em xử lý đầu vào của người dùng.

Tôi không chắc lý do tại sao Visual Studio đã bắt đầu phàn nàn về điều này ngay bây giờ (vì nó cho phép tôi làm điều đó trước), và tôi không chắc chắn làm thế nào để làm cho nó biến mất. Tốt hơn, tôi muốn làm điều đó mà không cần phải xác định một phương pháp mà chỉ cần gọi CheckReadiness. Điều gì gây ra cảnh báo này, điều gì khiến nó xuất hiện ngay bây giờ khi nó không cách đây một giờ, và làm thế nào tôi có thể làm cho nó biến mất mà không cần phải xử lý ít trong tất cả các lớp con?

Trả lời

7

Khai báo phương pháp cha mẹ ảo, ghi đè lên nó trong các lớp con và gọi

base.checkReadyness(sender, e); 

(hoặc derevation đó) từ bên trong lớp trẻ. Điều này cho phép tiến hóa thiết kế trong tương lai nói nếu bạn muốn làm một số mã kiểm tra lỗi cụ thể trước khi gọi trình xử lý sự kiện cha mẹ. Bạn có thể không cần phải viết hàng triệu trình xử lý sự kiện như thế này cho mỗi điều khiển, bạn chỉ có thể viết một cái, móc tất cả các điều khiển đến trình xử lý sự kiện này mà lần lượt gọi trình xử lý sự kiện của cha mẹ.

Một điều mà tôi đã lưu ý là nếu tất cả mã này đang được đặt trong một dll, thì bạn có thể gặp phải một hiệu suất nhấn cố gắng gọi một trình xử lý sự kiện từ bên trong một dll.

+0

Điều đó sẽ giải quyết được vấn đề, nhưng tôi đã hy vọng tránh được các trình xử lý lỗi cơ bản trống rỗng, do đó câu hỏi của tôi. – Merus

+0

Tôi không nghĩ rằng họ đang thừa, mặc dù bạn đang giữ các điều khiển và xử lý sự kiện về cơ bản cùng nằm ở cùng một vị trí.Điều này có thể (tùy thuộc vào cách bố trí mã) dẫn đến khả năng đọc tốt hơn của mã vv Chỉ của nó mà tất cả các công việc được thực hiện ở nơi khác! –

+0

Có vẻ như điều phải làm ... có vẻ như đó chỉ là vấn đề thiết kế ... –

0

Nếu sự kiện của bạn đã được xác định trong lớp cha mẹ của bạn, bạn không cần phải viết lại nó trong lớp con của bạn. Điều đó sẽ gây ra sự kiện cháy hai lần.

Xác minh xem đây có phải là điều đang xảy ra không. HTH :)

0

Bài viết này trên MSDN phải là một điểm khởi đầu tốt: Overriding Event Handlers with Visual Basic .NET. Hãy xem Cách Điều khoản xử lý có thể gây ra sự cố trong phần Bắt nguồn từ mục.

+0

Đó là bài viết Visual Basic. Vấn đề họ thảo luận sẽ không phải là vấn đề trong C#. Nó có thể giải thích tại sao VS barfs trên một cái gì đó mà phải là hợp pháp, mặc dù. –

0

Tại sao không khai báo phương thức này là ảo trong lớp cha và sau đó bạn có thể ghi đè lên nó trong các lớp dẫn xuất để thêm chức năng bổ sung?

+0

Vì vậy, tôi không phải viết các trình xử lý cho mỗi lớp giống hệt nhau. Đây là những điều khiển khá nhỏ. Không có thêm nhiều chức năng tôi cần. – Merus

0

Hãy quên rằng đó là trình xử lý sự kiện và chỉ thực hiện ghi đè phương thức thường xuyên thích hợp trong lớp con.

3

Tôi cũng đã xem xét vấn đề này, tôi đồng ý rằng có vẻ như bạn đang làm mọi thứ chính xác. Khai báo phương thức ảo là một work-around tốt nhất, không phải là một giải pháp.

Điều đang được thực hiện là hợp lệ - một điều khiển chỉ tồn tại trong lớp dẫn xuất và lớp dẫn xuất được gắn một trình xử lý sự kiện vào một trong các sự kiện của điều khiển đó. Thực tế là phương thức xử lý sự kiện được định nghĩa trong lớp cơ sở không phải ở đây cũng không có ở đó, nó có sẵn tại điểm ràng buộc với sự kiện. Sự kiện này không được gắn với hai lần hoặc bất cứ điều gì ngớ ngẩn như vậy, nó chỉ đơn giản là vấn đề nơi mà phương thức xử lý sự kiện được xác định.

Chắc chắn nó không phải là một phương pháp ảo - tôi không muốn phương thức có thể được ghi đè bởi một lớp dẫn xuất. Rất bực bội, và theo tôi, một lỗi trong dev-studio.

1

Tôi vừa mới gặp vấn đề chính xác Merus lần đầu tiên nâng lên và như những người khác đã đăng câu trả lời, tôi không rõ tại sao các đối tượng VS (hiện đang sử dụng Visual C# 2010 Express) có trình xử lý sự kiện được định nghĩa trong lớp cơ sở. Lý do tôi đăng câu trả lời là trong quá trình giải quyết vấn đề bằng cách làm cho mã lớp cơ sở là một phương thức được bảo vệ mà các lớp dẫn xuất đơn giản gọi trong trình xử lý sự kiện (về cơ bản trống) của chúng, tôi đã đổi tên cơ sở lại phương pháp lớp và nhận thấy rằng các nhà thiết kế VS ngừng phàn nàn. Tức là, nó đổi tên thành đăng ký trình xử lý sự kiện (vì vậy nó không còn tuân theo quy ước đặt tên trình xử lý sự kiện đặt tên của VS với ControlName_EventName), và điều đó dường như thỏa mãn nó. Khi tôi cố gắng đăng ký trình xử lý sự kiện cơ sở (bây giờ được đổi tên) dựa vào các điều khiển lớp dẫn xuất bằng cách nhập tên vào sự kiện VS thích hợp, nhà thiết kế đã tạo một trình xử lý sự kiện mới trong lớp dẫn xuất mà tôi đã xóa, để lại điều khiển lớp dẫn xuất đã đăng ký đến phương thức lớp cơ sở (event handler). Net, như bạn mong đợi, C# tìm thấy những gì chúng tôi muốn làm legit. Nó chỉ là nhà thiết kế VS không thích nó khi bạn theo quy ước đặt tên bộ điều khiển sự kiện của nhà thiết kế. Tôi không thấy sự cần thiết của nhà thiết kế để làm việc theo cách đó. Anywho, thời gian để tiếp tục.

0

Đây là những gì tôi đã làm để có được phương pháp cơ bản được gọi là trong một số hình thức tương tự, mỗi một trong số họ có một vài tính năng bổ sung cho những người chung:

 protected override void OnLoad(EventArgs e) 
    { 
     try 
     { 
      this.SuspendLayout(); 
      base.OnLoad(e); 

      foreach (Control ctrl in Controls) 
      { 
       Button btn = ctrl as Button; 
       if (btn == null) continue; 

       if (string.Equals(btn.Name, "btnAdd", StringComparison.Ordinal)) 
        btn.Click += new EventHandler(btnAdd_Click); 
       else if (string.Equals(btn.Name, "btnEdit", StringComparison.Ordinal)) 
        btn.Click += new EventHandler(btnEdit_Click); 
       else if (string.Equals(btn.Name, "btnDelete", StringComparison.Ordinal)) 
        btn.Click += new EventHandler(btnDelete_Click); 
       else if (string.Equals(btn.Name, "btnPrint", StringComparison.Ordinal)) 
        btn.Click += new EventHandler(btnPrint_Click); 
       else if (string.Equals(btn.Name, "btnExport", StringComparison.Ordinal)) 
        btn.Click += new EventHandler(btnExport_Click); 
      } 

Cơ hội của một thiếu sót của việc sử dụng quyền cố định tên nút trông giống với tôi như là cơ hội không dây hệ thống xử lý kế thừa bằng tay.

Lưu ý rằng bạn có thể cần phải kiểm tra cho.DesignMode này để bạn bỏ qua mã trong VS Designer ở tất cả, nhưng nó hoạt động tốt cho tôi ngay cả khi không có kiểm tra.

2

Tôi cũng đã gặp phải vấn đề này vì trong các phiên bản trước của VS, bạn có thể "kế thừa" các trình xử lý sự kiện. Vì vậy, các giải pháp tôi tìm thấy mà không cần phải ghi đè lên phương pháp chỉ đơn giản là để chỉ định xử lý sự kiện một nơi nào đó trong giai đoạn khởi tạo của biểu mẫu. Trong trường hợp của tôi, được thực hiện trong hàm khởi tạo (tôi chắc rằng OnLoad() cũng sẽ hoạt động):

public MyForm() 
    { 
     InitializeComponent(); 
     btnOK.Click += Ok_Click; 
    } 

... nơi trình xử lý Ok_Click nằm ở dạng cơ sở. Thức ăn cho sự suy nghĩ.

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