程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#入門知識 >> 【C#】分享一個彈出容器層,像右鍵菜單那樣召即來揮則去,

【C#】分享一個彈出容器層,像右鍵菜單那樣召即來揮則去,

編輯:C#入門知識

【C#】分享一個彈出容器層,像右鍵菜單那樣召即來揮則去,


適用於:.net2.0+ Winform項目

------------------201508261813更新(源碼有更新、Demo未更新)------------------

  • 重新繪制調整大小手柄(SizeGrip,右下角那個),因為系統自繪的太靠邊角,在XP下會蓋過那部分邊框,視覺體驗不好。改進如圖:

    新增的DrawSizeGrip方法就是繪制方法,是protected virtual的,所以如果你看不上我畫的這個,可以在子類重寫該方法畫你自己滿意的(題外,畫這個我還參考了VS2010的效果,不過是相反的,VS的是凸起效果,我這是塌陷style)
  • 支持四邊+四角全方位拖動改變浮動層尺寸,改善體驗。如圖:

注:浮動層是否可以調整大小是根據SizeGripStyle屬性決定,分3種情況:

  • SizeGripStyle為Show,則始終允許用戶調整大小,手柄會出現、鼠標移至邊緣邊角會產生視覺變化並可以拖動
  • SizeGripStyle為Hide,則始終禁止用戶調整大小,手柄不會出現、鼠標移至邊緣邊角不會產生視覺變化,也不可以拖動改變大小
  • SizeGripStyle為Auto,則在模式化打開(Modal為true,即通過ShowDialog打開的)時與Show一致,非模式化打開(Modal為false,通過Show打開)時與Hide一致,這也是原版Form的邏輯,只不過原版Form還會根據FormBorderStyle,但本類已將該屬性固化,所以請注意Auto這貨,建議始終顯式指定Show/Hide為妙

------------------201508251458更新------------------

  • 激活首控件之前是在OnShown中進行,經過研究,改為令TopMost=true,就能使浮動層與正常窗體有一致的激活首控件行為,同時省卻了對OnShown的重寫
  • 解決子控件有時沒有聚焦框(焦點虛線框)的問題。如圖:

注:最後的demo沒更新,請重新取FloatLayerBase.cs源碼就好

------------------201508240846原文(已更新)------------------

背景:

有時候我們需要開一個簡單的窗口來做一些事,例如輸入一些東西、點選一個item之類的,可能像這樣:

完了返回原窗體並獲取剛剛的輸入,這樣做並沒有什麼問題,但在幾天前我突然產生了一些想法:為什麼非得有板有眼的彈出一個窗體給用戶呢,是不是可以在按鈕附近迅速呈現一個層來做這些事呢,類似快捷菜單那樣,用戶高興就在裡面做一下該做的事,不高興就在其它地方點一下它就消失,本來很輕便快捷的操作,DUANG~彈出一個窗體來會不會令用戶心裡咯噔一下呢,感受層面的事情往往是很微妙的,不管怎樣,我既然起了這個念頭,just try it。

我首先找了一下現成的方案,果然在牛逼的codeproject.com已經有牛人做了這樣的事情:

http://www.codeproject.com/Articles/17502/Simple-Popup-Control

簡單體驗了一下,的確是了不起的創造。原理是利用ToolStripControlHost可以承載自定義控件的這一能力,讓下拉式控件ToolStripDropDown將任何自定義控件像右鍵菜單那樣彈出來(別忘了右鍵菜單ContextMenuStrip就是繼承自ToolStripDropDown),這樣就等於把菜單作為一個容器,可以彈出任何或簡單或復雜的控件組合,同時又具有菜單具有的便捷性,召之即來揮之即去。當時了解到這方案的時候真挺開心,正是我想要的效果,感覺這下好了,不用瞎費勁自己造了。

但很快發現一個在我看來還挺在意的不足,就是ToolStripDropDown只有Show,沒有ShowDialog,就是不能以模式化(Modal,也有叫模態的,鑒於MSDN都稱模式,我也隨流叫它模式)的方式彈出,這是由ToolStripDropDown的固有能力決定的,該方案既然基於ToolStripDropDown,自然也受限於此,不能模式化彈出。這樣帶來的問題是某些情況下的調用體驗不好(體驗這種事當然不是用戶才有的專利,俺們碼農也是人,也要講體驗的說),比如彈出的控件是讓用戶輸入一些東西,完了用戶點擊某個按鈕什麼的返回原窗體,然後在原窗體獲取用戶剛剛的輸入,然後接著做後面的事。由於非模式的Show不會阻塞代碼,所以就不能在Show的下方想當然的獲取值、使用值~這是顯然的。要想獲得值可能就得額外采取一些做法,例如響應彈出控件的關閉事件,或者把原窗體傳入彈出控件完了在後者中做原本應該在原窗體中做的事~等等,辦法當然有很多,但這都是因為只能Show帶來的多余的事,有什麼比在一個方法中彈出控件、等待返回、繼續處理來的爽滑的呢,像這樣不是很自然嗎:

string s;
using (Popup p = new Popup())
{
    if (p.ShowDialog() != DialogResult.OK) { return; }

    s = p.InputText;
}
//go on
...

所以很遺憾,不得不揮別這個優秀的方案,造自己的輪子。不過受該方案的啟發,我想到用ContextMenu來做容器(注意這個菜單類跟上面提到的繼承自ToolStripDropDown的ContextMenuStrip大大的不同,前者是OS原生的菜單,就是在桌面、圖標以及文本框中右鍵彈出的那種菜單,.net是通過調API的方式來操作這樣的菜單,而後者則完全是.net實現,更多信息請參考MSDN,此處不展開),因為ContextMenu的Show是阻塞式的,正合我意。但一番嘗試之後放棄,它的菜單項MenuItem不像ToolStripItem那樣可以通過ToolStripControlHost承載自定義控件,希望是我能力有限,總之我做不到把自定義控件弄到ContextMenu上,也沒見過原生菜單上出現過文本框、復選框等奇怪的東西,如果您知道怎麼擴展原生菜單,還望不吝賜教,先行謝過!

我還是打回.net的主意,當中仍然是做了許多不同的嘗試,Form、Panel、UserControl、ContainerControl、Control等等看起來適合做容器層的東西都試了個遍,甚至重新在ToolStripDropDown上打主意,最後選用Form,改造一番,自我感覺較理想的實現了我要的東西:一個叫做FloatLayerBase的基類,它本身繼承自System.Windows.Forms.Form類,而需要作為浮動層顯示的應用則繼承自FloatLayerBase進行實現,例如下面這個接受用戶輸入數值的NumInputDemo實現:

樣子和特點:

  • 不會令父窗口失去焦點(不會搶焦點的層才是好層):

    當然,男人不止一面:

    還有其它邊框樣式,有待用戶自行體驗,最後有demo提供。

  • 可以有調整尺寸的手柄

  • 可以點住客戶區拖動

別的一些應用:

這些都只是demo,沒那麼好看和強大,重點是有了這個FloatLayerBase,就可以實現自己的浮動應用。

使用說明:

其它:

編寫期間一直使用PopupFormBase作為類名,發布最後時刻才改為現在的FloatLayerBase,所以demo中可能尚有依據原名起名的子類、方法名等。

Demo下載:

http://pan.baidu.com/s/1mgnGPGc

裡面有個Tester供您體驗。

 

-文畢-

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved