2012-07-25 35 views
9

Tôi đang sử dụng System.Windows.Forms.ContextMenu. Tôi muốn làm cho nó như vậy khi bạn bấm vào một số các nút, nó không đóng menu. Ngay bây giờ tôi có nó hoạt động ở bất cứ đâu khi bạn nhấn vào nó, nó sẽ mở lại menu ở cùng một vị trí. Vấn đề duy nhất là nó có vẻ xấu bởi vì bạn có thể thấy nhấp nháy menu. Có cách nào tốt hơn để làm điều này không?C# WinForms - Giữ một ContextMenu đóng sau khi nhấp vào một số mục nhất định

Ngữ cảnh WPFMenu có thuộc tính StaysOpen, nhưng biểu mẫu Win không có. (Có cách nào tôi có thể sử dụng ContextMenu WPF?) Tôi không muốn sử dụng ContextMenuStrip, mà có thể làm điều này, bởi vì ContextMenu trông đẹp hơn rất nhiều.

Chỉnh sửa:

Tôi sẽ không đánh dấu đây là giải pháp vì việc làm điều này không tốt. Nếu bạn cần phải làm những gì câu hỏi của tôi yêu cầu, một cách sẽ được thực hiện một UserControl từ WPF, và sau đó đặt đối tượng với menu ngữ cảnh trong đó, sau đó thêm menu ngữ cảnh đó. Bây giờ bởi vì nó trong WPF, trên các nút mà bạn không muốn đóng menu khi nhấn, thiết lập thuộc tính StaysOpenOnClick thành true trên MenuItem. Sau đó, chỉ cần đặt UserControl này vào ứng dụng WinForms của bạn.

+0

Tôi đã quay lại và chấp nhận một số câu trả lời từ các câu hỏi khác của mình. Vào thời điểm tôi làm cho họ, tôi không biết bạn nên làm điều đó. – Aidan

+0

Không sao cả. Nó luôn luôn là tốt để chấp nhận câu trả lời là chính xác. Bằng cách đó, cộng đồng có thể xây dựng danh tiếng. – CodeLikeBeaker

Trả lời

4

Không có cách nào tốt để thực hiện việc này bằng cách sử dụng điều khiển ContextMenu. Đó chỉ là một trình bao bọc xung quanh các menu Win32 bản địa, đó là lý do tại sao nó trông tốt hơn rất nhiều. Nó được vẽ bằng API OS, giống như các menu trong tất cả các ứng dụng khác.

So sánh điều đó với điều khiển ContextMenuStrip, điều này hoàn toàn tùy chỉnh được vẽ bởi khung trong mã C#. Nó trông siêu mát mẻ (tôi đoán) trở lại khi nó lần đầu tiên được phát hành, khi Windows và Office XP là những sản phẩm mới nhất trên kệ. Khi Windows Vista tung ra, nó trở nên lỗi thời khủng khiếp. Lợi thế duy nhất nó hiện có là bạn có nhiều kiểm soát chi tiết hơn trên các menu. Ví dụ: bạn có thể lưu trữ các điều khiển tùy chỉnh trong menu và bạn có thể ngăn menu đóng khi bạn nhấp vào một trong các mục. Các trình đơn Win32 gốc không có hỗ trợ cho điều đó.

Tất nhiên, đó không chỉ là sự thiếu sót giám sát hoặc vô tình. Mong muốn giữ một menu ngữ cảnh mở sau khi người dùng đã chọn thứ gì đó là một đầu mối tốt mà thiết kế của bạn sai. Hãy nhớ rằng mục đích của menu ngữ cảnh là cung cấp cho người dùng quyền truy cập nhanh vào các tùy chọn có liên quan theo ngữ cảnh. Tất cả những gì họ phải làm là nhấp chuột phải (hoặc nhấn một nút đặc biệt trên bàn phím của họ) và họ có thể thấy trình đơn các lựa chọn liên quan trực tiếp đến những gì họ đang làm hoặc cố gắng hoàn thành. Cũng giống như một menu thông thường, chúng được cho là có khả năng chọn một tùy chọn và có trình đơn biến mất.

Trong Windows, tất cả các menu đều "tự động đóng". Nếu menu nên kiên trì, nó không phải là một thực đơn nào cả. Cân nhắc sử dụng thanh công cụ, thanh bên hoặc một số loại điều khiển tùy chỉnh thay thế. Những thứ đó không được thiết kế để biến mất khi một trong các tùy chọn của chúng được chọn và do đó chúng lý tưởng để hiển thị các tùy chọn liên quan nên luôn hiển thị.

Nếu menu ngữ cảnh trong ứng dụng không biến mất sau khi tôi đã chọn một tùy chọn, tôi cho rằng đó là lỗi. Ít nhất, tôi cho rằng lựa chọn của tôi không "mất" và thử nhấp lại vào lần nữa.

tôi không có đầu mối nhỏ lý do tại sao đội WPF quyết định cung cấp một lựa chọn StaysOpen cho menu ngữ cảnh của họ, hoặc tại sao họ viết lại lớp menu ngữ cảnh riêng của họ ở nơi đầu tiên. Chẳng phải họ đã học được điều gì đó từ đội WinForms đã làm điều tương tự chưa?

Cách duy nhất để làm những gì bạn đang yêu cầu với điều khiển ContextMenu (và do đó các menu gốc) là một bản hack tương tự như bạn mô tả — lưu trữ vị trí trước đó của menu và sau khi lệnh được chọn , reshow menu pop-up ở vị trí trước đó của nó. Bất cứ điều gì chữa bệnh bạn đưa ra cho nhấp nháy (ví dụ, đóng băng màn hình và đàn áp repaints cho đến khi menu ngữ cảnh được reshown) gần như được đảm bảo là tồi tệ hơn bệnh.

+0

Cảm ơn. Tôi biết bạn không phải là "nghĩa vụ" để làm điều đó như thế, nhưng trong tình huống của tôi, tôi nghĩ nó hoạt động tốt. Tôi có một TreeView, trong đó mỗi nút có thể có các tùy chọn boolean liên kết với nó. Tôi có một menu ngữ cảnh được gắn vào mỗi nút để thiết lập các tùy chọn đó và tôi không có bất kỳ phòng nào trong cửa sổ cho các nút hoặc hộp kiểm thực tế. Ngoài ra, các hộp kiểm sẽ cần phải truy cập dễ dàng vào TreeView, không phải trong cửa sổ bật lên hay gì đó. – Aidan

+2

Một chút trễ, nhưng tôi quên thêm: Các nút trong ContextMenu là các nút hộp kiểm, và tôi không muốn có menu đóng trong khi họ thay đổi trạng thái kiểm tra trong các nút. Bạn có thể thấy nó kiểm tra/bỏ chọn, vì vậy tôi không nghĩ rằng nó sẽ giống như một lỗi như bạn nói. – Aidan

+1

Trình đơn ngữ cảnh không đặc biệt có thể phát hiện được cho người dùng. Họ nên ở đó cho những người biết về họ và muốn sử dụng chúng, nhưng họ không nên hình thành phương thức tương tác chính với ứng dụng của bạn. Đề nghị của tôi sẽ là * tạo * chỗ cho một thanh công cụ nhỏ ở trên cùng hoặc dưới cùng của điều khiển TreeView. –

15

Bạn có thể giữ menu ngữ cảnh của bạn mở như thế này:

private bool CloseContextMenu = true; //Class Variable 

Sau đó, thêm MouseDown thậm chí đến bối cảnh mục menu của bạn:

private void menu1ToolStripMenuItem_MouseDown(object sender, MouseEventArgs e) 
{ 
    CloseContextMenu = false; 
} 

Sau đó, trên bối cảnh sự kiện đơn bế mạc của bạn:

private void contextMenuStrip1_Closing(object sender, ToolStripDropDownClosingEventArgs e) 
{ 
    e.Cancel = !CloseContextMenu; 
    CloseContextMenu = true; 
} 

Sau đó, bạn có thể thêm CloseContextMenu = false vào bất kỳ sự kiện menu nào bạn muốn.

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

+1

Cảm ơn, nhưng tôi đang nói về một ContextMenu, không phải là một ContextMenuStrip. Đáng buồn thay, sự kiện gần gũi của ContextMenu không có e.Cancel (ít nhất không phải là tôi biết). – Aidan

+0

Điều này có thể được đơn giản hóa thành: 'contextMenuStrip1.Closing + = (s, e) => e.Cancel = e.CloseReason == ToolStripDropDownCloseReason.ItemClicked;' Vẫn không hoạt động cho 'ContextMenu'. –

-1

Tôi chỉ cần thêm

ContextMenuStrip1.Show(); 

trong sự kiện click của tôi. Khi tôi nhấp vào menu ngữ cảnh, nó sẽ đóng, nhưng sẽ mở ngay lập tức, vì vậy nó vẫn mở được hiệu quả.

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