適用於:.net2.0+ Winform項目
------------------201508261813更新(源碼有更新、Demo未更新)------------------
注:浮動層是否可以調整大小是根據SizeGripStyle屬性決定,分3種情況:
------------------201508251458更新------------------
注:最後的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中可能尚有依據原名起名的子類、方法名等。
http://pan.baidu.com/s/1mgnGPGc
裡面有個Tester供您體驗。
-文畢-