現在,儘管WPF、UWP大行其道,大有把Winform打殘幹廢的趨勢。可是仍是有那麼一波頑固不化的老傢伙們固守着Winform,其中就包括我。css
好吧,既然都說Winform作得軟件不如WPF界面美觀效果絢麗,那麼咱們就找一個方法讓Winform也擁有漂亮的界面。DevExpress和ComponentOne都是不錯的選擇,Telerik雖然說是作Asp.net組件出生的,可是他家的UI for Winform作得也很不錯。稍等,那問題來了,這些組件收費昂貴不說,並且是年付,起價都得幾百美刀。對於我這種盧瑟程序員來講,是支付不起這樣高昂的費用的。那有人要說了,你咋不用破解版的呢?是的,能夠用,並且也在用,可是這樣一來個人心裏是無比糾結的,用破解的盜版的,我就得欠另外那羣程序員一大我的情,我這人雖然盧瑟,不喜歡欠別人人情!開個玩笑而已:)那麼,有沒有什麼開源的,免費的,好用的解決方案呢?html
研究了一段時間,本人發現用瀏覽器作殼用HTML和CSS呈現軟件界面是一種新趨勢,固然這裏指的瀏覽器不是.net本身帶的WebBroswer控件,緣由不用我多說,你們都明白。這裏說的是大名鼎鼎的CEF——Chromium Embedded Framework,通俗點也就是谷歌瀏覽器的核心了。CEF做爲一個開源的瀏覽器核心組件對HTML五、CSS3和JS標準的支持不用我過多介紹,都是極好的。目前不少大廠都在使用CEF做爲軟件界面呈現,好比鵝廠大名鼎鼎的微信桌面版,網易的雲音樂等等。因此,若是將CEF引入Winform做爲界面呈現也是可行的。git
CEF的.net實現衆多,最後相中了CefSharp和ChromimunFX兩個開源項目,對比之,CefSharp除了傳統的瀏覽器功能外還實現了離屏渲染,可是做爲Winform忠狗的我來講,我並不須要離屏渲染這項高端技術。最終ChromiumFX使用PInvoke的方式調用CEF的API,更接近「原生」,也更利於定製。通過個把月的披星戴月,在ChromiumFX的基礎上本人完成了本身的CEF界面封裝,暫時命名爲NanUI for Winform,目前處於預覽階段。程序員
那麼,下面就來看看本人封裝的NanUI完成了什麼工做。上圖先~~github
NanUI目前處於預覽開發階段,還有一些問題並未解決,所以暫時不傳GitHub,等穩定一些會考慮開放源代碼。web
目前實現的功能:chrome
那麼,下面分項介紹上面列舉的功能。api
你覺得這裏的無標題窗口就是單純的把FormBorderStyle設置爲None嗎?固然不是。實現基礎是調用DWM的DwmExtendFrameIntoClientArea,而後重繪了下窗口的邊框,處理了各類鼠標事件。那有人要問了,那做着些事情不是狗解手嗎,直接FormBorderStyle設置個None不就解決了?是的,這是能夠解決,可是窗口就喪失了各類投影效果,各類放大縮小的效果。其次,還有各類鼠標消息和HITTEST消息,須要從ChromiumFX中傳遞到窗體上,要否則ChromiumFX一旦Dock而後Fill到窗口上,窗口還會相應鼠標事件纔怪。因此,做爲UI的基礎,拖拽、放大、縮小等基本的操做都實現了。瀏覽器
在網頁元素的css裏打上「-webkit-app-region:drag」標記,就能夠實現拖動該元素來移動窗體。服務器
如圖所示,須要拖動的地方,就是drag,在標記過drag的元素上某些不給拖動的位置(例如關閉,最大化,最小化按鈕位置)打上no-drag就拖動不了了。
其餘沒標記的地方隨意,拖動事件會直接交給JS。
NanUI支持將作好的網頁html、css、js、圖片等文件直接做爲嵌入資源編譯到當前項目或者獨立的DLL中,框架會自動調用嵌入的網頁資源。既然用HTML作界面,HTML暴露在外被別人想改就改,那這個軟件跟鹹魚有什麼區別?因此網頁文件做爲內嵌資源功能被做爲NanUI的核心功能之一,資源內嵌後,再給程序集加個強命,那要改你的軟件就沒那麼簡單了吧。
這也是本人爲何不選擇CefSharp的的緣由之一,CefSharp只支持編譯成單一目標,很是不方便。ChromiumFX可以自動識別客戶機環境加載對於的x86或是x64庫。在此基礎上NanUI擴展了自動下載CEF相關文件的功能,換句話說,發佈項目的時候只須要發佈項目自己生成的程序和程序集就能夠了,軟件首次在客戶機運行時,會根據客戶機的環境自動從指定網絡位置下載CEF的相關文件,這樣的好處就是軟件發佈的時候不用在軟件自己內置CEF相關文件,極大的減少了打包文件的大小,並且不用去考慮客戶機是32位系統仍是64位系統,簡化發佈流程。例如微信Windows客戶端,安裝包30多兆,其中至少25M是CEF相關文件,並且,微信客戶端只有一個x86的版本,NanUI很好的規避了這個問題,文章最後的示例程序能夠很好的證實這點。
最開始我就說了NanUI基於ChromiumFX開發,ChromiumFX原本應該有什麼樣的功能,NanUI就支持什麼樣的功能。要實現網頁JS調用C#的類、方法等,C#操做網頁DOM元素等,均可以經過ChromiumFX來實現。更多的功能,將會在後面的文章來介紹。
NanUI的基本功能就是上面說的這些。有了NanUI對Winform程序的支持,想作什麼樣的界面均可以實現了,不管是模仿個微信Window客戶端、網易雲音樂,仍是模擬下Win10裏UWP那種款式的應用都是不在話下的。
下面,我講介紹下NanUI的基本使用方法。
NanUI文件結構
NetDimension.NanUI.dll NetDimension.ZipCompress.dll
NanUI結構很是簡單,「NetDimension.NanUI.dll」封裝了ChromiumFX的所有內容並作了一些必要的修改,除此以外的其餘內容就是NanUI的核心部分了。「NetDimension.ZipCompress.dll」是一個操做Zip文件的庫,內容剽竊自DotNetZip,並作了一些修改。在此特別說明下,不論CEF、ChromiumFX仍是DotNetZip都採用BSD開源協議,協議容許我對上述項目進行剽竊、修改和隨便用於商業目的,哦呵呵,因此別罵我無恥。
迴歸正題,在新建項目中引用「NetDimension.NanUI.dll」庫便可。「NetDimension.ZipCompress.dll」僅做爲須要遠程下載CEF庫時作解壓ZIP文件用,實際項目中並不須要引用,若是項目發佈時已在本地內嵌CEF框架,那麼這個解壓縮的庫不須要隨軟件分發。
在此特別說明下CEF框架的文件夾結構:
fx與程序集放置在同一層級,若是項目編譯時特地選擇了x86架構或x64架構時,另一種架構的文件夾是不須要存在的,僅當項目編譯類型爲any cpu時須要x86和x64文件同時存在,NanUI會根據客戶機的運行環境來自動選擇加載x86或是x64架構的CEF庫。當fx存在的時候NanUI將不會啓用CEF庫下載的特性,僅當fx文件夾內的CEF框架不存在時,NanUI纔會自動從遠程服務器下載CEF框架文件。
接下來,在Main函數中作一些簡單的初始化的工做。
[STAThread] static void Main() { Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); UIStartupManager.UseSharedFramework = true; if(UIStartupManager.InitializeChromium(args=> { args.Settings.LogSeverity = Chromium.CfxLogSeverity.Default; //這裏能夠對CEF進行一些設定 },args=> { Console.WriteLine(args.CommandLine); //輸出命令行開關,看看啓用或是禁用了哪些功能 })) { //初始化成功,加載程序集內嵌的資源到運行時中,固然也能夠加載其餘程序集裏面的資源。 UIStartupManager.RegisterEmbeddedScheme(System.Reflection.Assembly.GetExecutingAssembly()); //啓動主窗體 Application.Run(new frmWelcome()); } }
主窗體
public partial class frmWelcome : HtmlUIForm //繼承HtmlUIForm { frmAbout aboutForm = null; public frmWelcome() : base("embedded://www/index.html") //設定啓示頁面,scheme是embedded就是咱們在Main裏註冊的當前程序集資源 { InitializeComponent(); //在js中註冊一個方法來打開About窗口 UI.GlobalObject.AddFunction("showAboutForm").Execute += (sender, args) => { ShowAboutWindow(); }; //網頁加載完成時觸發事件 UI.LoadHandler.OnLoadEnd += (sender, args) => { //判斷下觸發的事件是否是主框架的 if(args.Frame.IsMain) { //執行JS,將當前的CEF運行版本等信息經過JS加載到網頁上 var js = $"$client.setRuntimeInfo({{ api: ['{CfxRuntime.ApiHash(0)}', '{CfxRuntime.ApiHash(1)}'], cef:'{CfxRuntime.GetCefVersion()}', chrome:'{CfxRuntime.GetChromeVersion()}',os:'{CfxRuntime.PlatformOS}', arch:'{CfxRuntime.PlatformArch}'}});"; UI.ExecuteJavascript(js); } }; } private void ShowAboutWindow() { //由於當前環境中的JS代碼跑在另外的線程上,因此在Control上擴展個UpdateUI方法,簡化InvokeRequired流程 this.UpdateUI(() => { //顯示字窗體的過程,不解釋 if (aboutForm == null || aboutForm.IsDisposed) { aboutForm = new frmAbout(); aboutForm.Show(this); } else { aboutForm.Activate(); } }); } }
就是這麼簡單幾步,漂亮的HTML界面加載到了你的Winform上,固然,前提是你得先有個「漂亮」的HTML界面先:)
好了,就像上面的圖片裏展現的同樣,經過NanUI,Winform一樣可以作出像其餘兩款軟件那樣的界面了。NanUI的預覽版就先介紹到這裏。在後續的文章中,我將以項目的形式再來深度的介紹NanUI在Winform中的各類運用。
下面的會提供上述圖片中展現的DEMO程序及源代碼提供給有興趣的朋友下載把玩。
DEMO是用VS2015在Win10下編寫的,.net須要4.5版本(Win10免安裝,其餘系統自行Google下載安裝)可以運行。
感謝觀看,謝謝你們,歡迎拍磚。
-------------------------------------------------- 分隔線 ----------------------------------------------------
應園友的要求,把NanUI所用技術的開源鏈接放置在此:
ChromiumFX - https://bitbucket.org/chromiumfx/chromiumfx
DotNetZip - https://github.com/haf/DotNetZip.Semverd .net 4.5的System.IO.Compress下面有操做Zip的類,正考慮要不要換成.net自帶的,換了之後整個項目就只支持4.5了。
另一個CEF的.net實現
CefSharp - https://github.com/cefsharp/CefSharp/ NanUI最初的版本使用CefSharp做爲基礎,可是有些問題始終解決不了,才又轉到ChromiumFX的。
另外今天看了評論,感謝各位提供了其餘UI框架,不少以前都沒見過,因此真是學習長進了。
也有朋友提出不少界面效果用WPF就能夠實現,那問題來了,我不會WPF呀,呵呵,由於作過幾年網頁狗,因此仍是對HTML五、CSS3和Javascript要更親切點。對於WPF和XAML,確實很強大,但路有多條,本着鑽研的精神,應懷開放的態度,任何事物都能拿來嘗試和學習。
NanUI也是機緣巧合之下研究了CEF纔有想法作這麼一個項目的。當時在跟某銀行用了EXTJS作系統,爲了客戶端瀏覽器能正確加載EXTJS,解決方案就是Winform+CEF加殼硬把一個BS改爲了客戶端,因此後來了解了CefSharp項目,由於能力和學識有限,用CefSharp做爲UI基礎的時候有幾個問題始終解決不了,所以才又發掘了ChromiumFX。
還有朋友提出NanUI有卵用?我的以爲,存在即合理。既然騰訊,網易能用CEF弄出微信Windows客戶端,網易雲音樂,既然Cef永遠甩不掉體積大的問題,我相信出於種種考慮,這兩家大公司最終在其面向終端用戶的應用軟件中赤裸裸的、不計軟件體積的引用了Cef,那咱們這些.net狗winform狗爲什麼不能拿CEF來作成Winform的界面殼呢?
我的拙見,歡迎討論回覆討論或進羣討論,羣號:241088256
NanUI for .NET Winform系列目錄
通過了這一個多星期的調整與修復,NanUI for .NET Winform的穩定版已經發布。應廣大羣友的要求,現已將NanUI的所有代碼開源。
GitHub: https://github.com/NetDimension/NanUI
Release: https://github.com/NetDimension/NanUI/releases
若是你喜歡NanUI項目,你能夠參與到NanUI的開發中來,固然你也能夠更直接了當的支持個人工做,使用支付寶或微信掃描下面二維碼請我喝一杯熱騰騰的咖