C# 封装miniblink 使用HTML/CSS/JS来构建.Net 应用程序界面和简易浏览器

MiniBlink的作者是 龙泉寺扫地僧

miniblink是什么?   (抄了一下 龙泉寺扫地僧 写的简洁)

Miniblink是一个全新的、追求极致小巧的浏览器内核项目,
其基于chromium最新版内核,去除了chromium所有多余的部件,只保留最基本的排版引擎blink。
Miniblink保持了10M左右的极简大小,是所有同类产品最小的体积,同时支持windows xp、npapi。

为什么要做miniblink?

市面上作为嵌入的组件的可用的浏览器内核,不外乎这几个:webkit、cef、nwjs、electron。

cef:优点是由于集成的chromium内核,所以对H5支持的很全,同时因为使用的人也多,各种教程、示例,资源很多。但缺点很明显,太大了。最新的cef已经夸张到了100多M,还要带一堆的文件。同时新的cef已经不支持xp了(chromium对应版本是M49)。而且由于是多进程架构,对资源的消耗也很夸张。如果只是想做个小软件,一坨文件需要带上、超大的安装包,显然不能忍受。

nwjs,或者最近大火的electron:和cef内核类似,都是chromium内核。缺点和cef一模一样。优点是由于可以使用nodejs的资源,同时又自带了各种api的绑定,所以可以用的周边资源非常丰富;而基于js的开发方案,使得前端很容易上手。所以最近N多项目都是基于nwjs或electron来实现。例如vscode,atom等等。

原版webkit:现在官网还在更新windows port,但显然漫不在心,而且最新的webkit也很大了,超过20几M。最关键的是,周边资源很少,几乎没人再基于webkit来做开发。同时由于windows版的saferi已经停止开发了,所以用webkit就用不了他的dev tools了。这是个大遗憾。

WKE:这是个很老的webkit内核的裁剪版了。小是小,但bug太多了。

那么关键点来了,使用miniblink有啥好处呢??

首先,miniblink对大小要求非常严格。原版chromium、blink里对排版渲染没啥大用的如音视频全都被砍了,只专注于网页的排版和渲染。甚至为了裁剪大小,我不惜使用vc6的crt来跑mininblink。这个也算前无古人后无来者了。

其次,miniblink紧跟最新chromium,这意味着chromium相关的资源都可以利用。在未来的规划里,我是打算把electron的接口也加上的,这样可以无缝替换electron。使用miniblink的话,开发调试时用原版electron,发布的时候再替换掉那些dll,直接可以无缝切换,非常方便。

 

miniblink如何裁剪到这么小?

这个比较复杂了。主要就是把blink从chromium抽离了出来,同时补上了cc层(硬件渲染层)。现在的blink,已经不是当年的那个webkit了,渲染部分全走cc层,复杂无比。我这大半年都在重写他那个蛋疼又复杂的cc层。

和webkit比,miniblink架构有什么优势

现在的webkit版本,已经比miniblink落后太多了。blink一直在加入各种极富创造力和想象力的功能、组件。例如,blink早就加入多线程解析html token、blink gc回收器、多线程录制回放渲染机制。这些能让blink的解析渲染速度极大提升。下一次,我会先开源出blink gc组件,这东西很有意思,在c++里硬是搞出了一个垃圾回收机制,能让你像写java一样写c++。

miniblink 开源地址:https://github.com/weolar/miniblink49

我们可以通过miniblink做桌面应用的UI,超小的附加dll,压缩之后大约5M,比起Cefsharp 小太多了。VSCode也是用  Electron 网页开发的

Html开发UI和WPF对比有什么优势?

1、 Html 前端资源丰富,各种框架

2、 会Html的人比会WPF的人多太多了,入门简单

3、.Net2.0照样可以用

4、网站和桌面程序界面可以统一,甚至大部分前端代码复用

资源消耗方面,和WPF差不多,毕竟浏览器也是内存消耗大户

不过对比electron 这种纯 Html CSS + js的,我更喜欢 用C# 代替JS 做业务逻辑,我感觉JS写大项目 代码比较乱,维护比C#麻烦。所以 JS做前端辅助比较合适,业务逻辑用C#实现

接下来,我写个简单的MiniBlink封装案例!更多功能你们可以自行封装 或者 看看 DSkin

采用 PInvoke 和Winform封装方式,MiniBlink对外提供的接口主要在 wke.h ,miniblink 的dll可以通过GitHub源码编译出来。具体封装规则,你们可以百度查查看

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Text;
  5 using System.Runtime.InteropServices;
  6 //by:DSkin
  7 
  8 namespace MiniBlink
  9 {
 10     public static class MiniblinkPInvoke
 11     {
 12         const string miniblinkdll = "node.dll";
 13 
 14 
 15         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 16         public static extern void wkeSetHandle(IntPtr webView, IntPtr wnd);
 17 
 18         [DllImport(miniblinkdll, CharSet = CharSet.Unicode)]
 19         public static extern IntPtr wkeGetStringW(IntPtr @string);
 20 
 21         [DllImport(miniblinkdll, CharSet = CharSet.Unicode)]
 22         public static extern IntPtr wkeToStringW(IntPtr @string);
 23 
 24         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 25         public static extern IntPtr wkeGetString(IntPtr @string);
 26 
 27         [DllImport(miniblinkdll)]
 28         public static extern void wkeSetDebugConfig(IntPtr webView, string debugString, IntPtr param);
 29 
 30         [DllImport(miniblinkdll)]
 31         public static extern Int64 wkeRunJSW(IntPtr webView, [In] [MarshalAs(UnmanagedType.LPWStr)] string script);
 32 
 33         [return: MarshalAs(UnmanagedType.I1)]
 34         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 35         public static extern bool wkeFireMouseEvent(IntPtr webView, uint message, int x, int y, uint flags);
 36 
 37         [return: MarshalAs(UnmanagedType.I1)]
 38         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 39         public static extern bool wkeFireMouseWheelEvent(IntPtr webView, int x, int y, int delta, uint flags);
 40 
 41         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 42         [return: MarshalAs(UnmanagedType.I1)]
 43         public static extern bool wkeFireKeyUpEvent(IntPtr webView, uint virtualKeyCode, uint flags, [MarshalAs(UnmanagedType.I1)] bool systemKey);
 44 
 45         [return: MarshalAs(UnmanagedType.I1)]
 46         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 47         public static extern bool wkeFireKeyDownEvent(IntPtr webView, uint virtualKeyCode, uint flags, [MarshalAs(UnmanagedType.I1)] bool systemKey);
 48 
 49         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 50         [return: MarshalAs(UnmanagedType.I1)]
 51         public static extern bool wkeFireKeyPressEvent(IntPtr webView, uint charCode, uint flags, [MarshalAs(UnmanagedType.I1)] bool systemKey);
 52 
 53         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 54         public static extern void wkeSetFocus(IntPtr webView);
 55 
 56         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 57         public static extern void wkeKillFocus(IntPtr webView);
 58 
 59         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 60         public static extern void wkeResize(IntPtr webView, int w, int h);
 61 
 62         [DllImport(miniblinkdll)]
 63         public static extern IntPtr wkeCreateWebView();
 64 
 65         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 66         public static extern void wkeDestroyWebView(IntPtr webView);
 67 
 68         [DllImport(miniblinkdll)]
 69         public static extern void wkeInitialize();
 70 
 71         [DllImport(miniblinkdll)]
 72         public static extern void wkeLoadFile(IntPtr webView, [In, MarshalAs(UnmanagedType.LPWStr)] string filename);
 73 
 74         [DllImport(miniblinkdll)]
 75         public static extern void wkeLoadHTML(System.IntPtr webView, [In()] [MarshalAs(UnmanagedType.LPStr)] string html);
 76 
 77         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 78         public static extern void wkeOnURLChanged2(IntPtr webView, UrlChangedCallback2 callback, IntPtr callbackParam);
 79 
 80         [DllImport(miniblinkdll, CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
 81         public static extern void wkeLoadURLW(IntPtr webView, [In, MarshalAs(UnmanagedType.LPWStr)] string url);
 82 
 83         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 84         public static extern void wkeOnPaintUpdated(IntPtr webView, wkePaintUpdatedCallback callback, IntPtr callbackParam);
 85 
 86         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 87         public static extern void wkePaint(IntPtr webView, IntPtr bits, int pitch);
 88         [DllImport(miniblinkdll, CallingConvention = CallingConvention.Cdecl)]
 89         public static extern WkeCursorInfo wkeGetCursorInfoType(IntPtr webView);
 90 
 91         public static string Utf8IntptrToString(this IntPtr ptr)
 92         {
 93             var data = new List<byte>();
 94             var off = 0;
 95             while (true)
 96             {
 97                 var ch = Marshal.ReadByte(ptr, off++);
 98                 if (ch == 0)
 99                 {
100                     break;
101                 }
102                 data.Add(ch);
103             }
104             return Encoding.UTF8.GetString(data.ToArray());
105         }
106      //调用这个之后要手动调用  Marshal.FreeHGlobal(ptr);
107         public static IntPtr Utf8StringToIntptr(this string str)
108         {
109             byte[] utf8bytes = Encoding.UTF8.GetBytes(str);
110             IntPtr ptr = Marshal.AllocHGlobal(utf8bytes.Length + 1);
111             Marshal.Copy(utf8bytes, 0, ptr, utf8bytes.Length);
112             Marshal.WriteByte(ptr, utf8bytes.Length, 0);
113             return ptr;
114         }
115 
116 
117         public enum WkeCursorInfo
118         {
119             WkeCursorInfoPointer = 0,
120             WkeCursorInfoCross = 1,
121             WkeCursorInfoHand = 2,
122             WkeCursorInfoIBeam = 3,
123             WkeCursorInfoWait = 4,
124             WkeCursorInfoHelp = 5,
125             WkeCursorInfoEastResize = 6,
126             WkeCursorInfoNorthResize = 7,
127             WkeCursorInfoNorthEastResize = 8,
128             WkeCursorInfoNorthWestResize = 9,
129             WkeCursorInfoSouthResize = 10,
130             WkeCursorInfoSouthEastResize = 11,
131             WkeCursorInfoSouthWestResize = 12,
132             WkeCursorInfoWestResize = 13,
133             WkeCursorInfoNorthSouthResize = 14,
134             WkeCursorInfoEastWestResize = 15,
135             WkeCursorInfoNorthEastSouthWestResize = 16,
136             WkeCursorInfoNorthWestSouthEastResize = 17,
137             WkeCursorInfoColumnResize = 18,
138             WkeCursorInfoRowResize = 19,
139         }
140         public enum wkeMouseMessage : uint
141         {
142             WKE_MSG_MOUSEMOVE = 0x0200,
143             WKE_MSG_LBUTTONDOWN = 0x0201,
144             WKE_MSG_LBUTTONUP = 0x0202,
145             WKE_MSG_LBUTTONDBLCLK = 0x0203,
146             WKE_MSG_RBUTTONDOWN = 0x0204,
147             WKE_MSG_RBUTTONUP = 0x0205,
148             WKE_MSG_RBUTTONDBLCLK = 0x0206,
149             WKE_MSG_MBUTTONDOWN = 0x0207,
150             WKE_MSG_MBUTTONUP = 0x0208,
151             WKE_MSG_MBUTTONDBLCLK = 0x0209,
152             WKE_MSG_MOUSEWHEEL = 0x020A,
153         }
154         public enum wkeMouseFlags
155         {
156             WKE_LBUTTON = 0x01,
157             WKE_RBUTTON = 0x02,
158             WKE_SHIFT = 0x04,
159             WKE_CONTROL = 0x08,
160             WKE_MBUTTON = 0x10,
161         }
162 
163 
164         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
165         public delegate void wkePaintUpdatedCallback(IntPtr webView, IntPtr param, IntPtr hdc, int x, int y, int cx, int cy);
166 
167         [UnmanagedFunctionPointer(CallingConvention.Cdecl)]
168         public delegate void UrlChangedCallback2(IntPtr webView, IntPtr param, IntPtr frameId, IntPtr url);
169     }
170 }
  1 using System;
  2 using System.Collections;
  3 using System.Collections.Generic;
  4 using System.ComponentModel;
  5 using System.Drawing;
  6 using System.Drawing.Imaging;
  7 using System.IO;
  8 using System.Linq;
  9 using System.Reflection;
 10 using System.Runtime.InteropServices;
 11 using System.Text;
 12 using System.Text.RegularExpressions;
 13 using System.Windows.Forms;
 14 //by:DSkin
 15 
 16 namespace MiniBlink
 17 {
 18     public class TestControl : Control
 19     {
 20         IntPtr handle = IntPtr.Zero;
 21         string url = string.Empty;
 22 
 23         IntPtr bits = IntPtr.Zero;
 24         Size oldSize;
 25         MiniblinkPInvoke.UrlChangedCallback2 UrlChangedCallback2;
 26         MiniblinkPInvoke.wkePaintUpdatedCallback wkePaintUpdatedCallback;
 27 
 28         public TestControl()
 29         {
 30             SetStyle(ControlStyles.OptimizedDoubleBuffer |
 31             ControlStyles.DoubleBuffer |
 32             ControlStyles.AllPaintingInWmPaint |
 33             ControlStyles.ResizeRedraw |
 34             ControlStyles.UserPaint, true);
 35         }
 36 
 37         public string Url
 38         {
 39             get
 40             {
 41                 return url;
 42             }
 43 
 44             set
 45             {
 46                 url = value;
 47                 if (handle != IntPtr.Zero)
 48                 {
 49                     MiniblinkPInvoke.wkeLoadURLW(handle, value);
 50                 }
 51             }
 52         }
 53 
 54         protected override void OnCreateControl()
 55         {
 56             base.OnCreateControl();
 57             if (!DesignMode)
 58             {
 59                 MiniblinkPInvoke.wkeInitialize();
 60                 handle = MiniblinkPInvoke.wkeCreateWebView();//创建 WebView
 61                 MiniblinkPInvoke.wkeSetHandle(handle, this.Handle);
 62                 MiniblinkPInvoke.wkeResize(handle, Width, Height);
 63 
 64                 UrlChangedCallback2 = (webView, param, frameId, url) =>
 65                 {
 66                     this.url = MiniblinkPInvoke.wkeGetString(url).Utf8IntptrToString();
 67                     OnUrlChanged(EventArgs.Empty);
 68                 };
 69                 MiniblinkPInvoke.wkeOnURLChanged2(handle, UrlChangedCallback2, IntPtr.Zero);
 70 
 71                 wkePaintUpdatedCallback = (IntPtr webView, IntPtr param, IntPtr hdc, int x, int y, int cx, int cy) =>
 72                 {
 73                     Invalidate();
 74                 };
 75                 MiniblinkPInvoke.wkeOnPaintUpdated(handle, wkePaintUpdatedCallback, IntPtr.Zero);
 76 
 77                 Url = url;
 78             }
 79         }
 80 
 81         protected override void OnPaint(PaintEventArgs e)
 82         {
 83             if (handle != IntPtr.Zero)
 84             {
 85                 if (bits == IntPtr.Zero || oldSize != Size)
 86                 {
 87                     if (bits != IntPtr.Zero)
 88                     {
 89                         Marshal.FreeHGlobal(bits);
 90                     }
 91                     oldSize = Size;
 92                     bits = Marshal.AllocHGlobal(Width * Height * 4);
 93                 }
 94 
 95                 MiniblinkPInvoke.wkePaint(handle, bits, 0);
 96                 using (Bitmap bmp = new Bitmap(Width, Height, Width * 4, PixelFormat.Format32bppPArgb, bits))
 97                 {
 98                     e.Graphics.DrawImage(bmp, 0, 0);
 99                 }
100             }
101             base.OnPaint(e);
102             if (DesignMode)
103             {
104                 e.Graphics.DrawString("MiniBlinkBrowser", this.Font, Brushes.Red, new Point());
105                 e.Graphics.DrawRectangle(Pens.Black, new Rectangle(0, 0, Width - 1, Height - 1));
106             }
107         }
108 
109         protected override void OnSizeChanged(EventArgs e)
110         {
111             base.OnSizeChanged(e);
112             if (handle != IntPtr.Zero && Width > 1 && Height > 1)
113             {
114                 MiniblinkPInvoke.wkeResize(handle, Width, Height);
115             }
116         }
117 
118         protected override void OnMouseWheel(MouseEventArgs e)
119         {
120             base.OnMouseWheel(e);
121             if (handle != IntPtr.Zero)
122             {
123                 uint flags = GetMouseFlags(e);
124                 MiniblinkPInvoke.wkeFireMouseWheelEvent(handle, e.X, e.Y, e.Delta, flags);
125             }
126         }
127         protected override void OnMouseDown(MouseEventArgs e)
128         {
129             base.OnMouseDown(e);
130             uint msg = 0;
131             if (e.Button == MouseButtons.Left)
132             {
133                 msg = (uint)MiniblinkPInvoke.wkeMouseMessage.WKE_MSG_LBUTTONDOWN;
134             }
135             else if (e.Button == MouseButtons.Middle)
136             {
137                 msg = (uint)MiniblinkPInvoke.wkeMouseMessage.WKE_MSG_MBUTTONDOWN;
138             }
139             else if (e.Button == MouseButtons.Right)
140             {
141                 msg = (uint)MiniblinkPInvoke.wkeMouseMessage.WKE_MSG_RBUTTONDOWN;
142             }
143             uint flags = GetMouseFlags(e);
144             if (handle != IntPtr.Zero)
145             {
146                 MiniblinkPInvoke.wkeFireMouseEvent(handle, msg, e.X, e.Y, flags);
147             }
148         }
149         protected override void OnMouseUp(MouseEventArgs e)
150         {
151             base.OnMouseUp(e);
152             uint msg = 0;
153             if (e.Button == MouseButtons.Left)
154             {
155                 msg = (uint)MiniblinkPInvoke.wkeMouseMessage.WKE_MSG_LBUTTONUP;
156             }
157             else if (e.Button == MouseButtons.Middle)
158             {
159                 msg = (uint)MiniblinkPInvoke.wkeMouseMessage.WKE_MSG_MBUTTONUP;
160             }
161             else if (e.Button == MouseButtons.Right)
162             {
163                 msg = (uint)MiniblinkPInvoke.wkeMouseMessage.WKE_MSG_RBUTTONUP;
164             }
165             uint flags = GetMouseFlags(e);
166             if (handle != IntPtr.Zero)
167             {
168                 MiniblinkPInvoke.wkeFireMouseEvent(handle, msg, e.X, e.Y, flags);
169             }
170         }
171         protected override void OnMouseMove(MouseEventArgs e)
172         {
173             base.OnMouseMove(e);
174             if (this.handle != IntPtr.Zero)
175             {
176                 uint flags = GetMouseFlags(e);
177                 MiniblinkPInvoke.wkeFireMouseEvent(this.handle, 0x200, e.X, e.Y, flags);
178 
179                 switch (MiniblinkPInvoke.wkeGetCursorInfoType(handle))
180                 {
181                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoPointer:
182                         Cursor = Cursors.Default;
183                         break;
184                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoCross:
185                         Cursor = Cursors.Cross;
186                         break;
187                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoHand:
188                         Cursor = Cursors.Hand;
189                         break;
190                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoIBeam:
191                         Cursor = Cursors.IBeam;
192                         break;
193                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoWait:
194                         Cursor = Cursors.WaitCursor;
195                         break;
196                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoHelp:
197                         Cursor = Cursors.Help;
198                         break;
199                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoEastResize:
200                         Cursor = Cursors.SizeWE;
201                         break;
202                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoNorthResize:
203                         Cursor = Cursors.SizeNS;
204                         break;
205                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoNorthEastResize:
206                         Cursor = Cursors.SizeNESW;
207                         break;
208                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoNorthWestResize:
209                         Cursor = Cursors.SizeNWSE;
210                         break;
211                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoSouthResize:
212                         Cursor = Cursors.SizeNS;
213                         break;
214                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoSouthEastResize:
215                         Cursor = Cursors.SizeNWSE;
216                         break;
217                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoSouthWestResize:
218                         Cursor = Cursors.SizeNESW;
219                         break;
220                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoWestResize:
221                         Cursor = Cursors.SizeWE;
222                         break;
223                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoNorthSouthResize:
224                         Cursor = Cursors.SizeNS;
225                         break;
226                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoEastWestResize:
227                         Cursor = Cursors.SizeWE;
228                         break;
229                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoNorthEastSouthWestResize:
230                         Cursor = Cursors.SizeAll;
231                         break;
232                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoNorthWestSouthEastResize:
233                         Cursor = Cursors.SizeAll;
234                         break;
235                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoColumnResize:
236                         Cursor = Cursors.Default;
237                         break;
238                     case MiniblinkPInvoke.WkeCursorInfo.WkeCursorInfoRowResize:
239                         Cursor = Cursors.Default;
240                         break;
241                     default:
242                         Cursor = Cursors.Default;
243                         break;
244                 }
245             }
246         }
247         protected override void OnKeyDown(KeyEventArgs e)
248         {
249             base.OnKeyDown(e);
250             if (handle != IntPtr.Zero)
251             {
252                 MiniblinkPInvoke.wkeFireKeyDownEvent(handle, (uint)e.KeyValue, 0, false);
253             }
254         }
255         protected override void OnKeyPress(KeyPressEventArgs e)
256         {
257             base.OnKeyPress(e);
258             if (handle != IntPtr.Zero)
259             {
260                 e.Handled = true;
261                 MiniblinkPInvoke.wkeFireKeyPressEvent(handle, (uint)e.KeyChar, 0, false);
262             }
263         }
264         protected override void OnKeyUp(KeyEventArgs e)
265         {
266             base.OnKeyUp(e);
267             if (handle != IntPtr.Zero)
268             {
269                 MiniblinkPInvoke.wkeFireKeyUpEvent(handle, (uint)e.KeyValue, 0, false);
270             }
271         }
272 
273         protected override void OnGotFocus(EventArgs e)
274         {
275             base.OnGotFocus(e);
276             if (handle != IntPtr.Zero)
277             {
278                 MiniblinkPInvoke.wkeSetFocus(handle);
279             }
280         }
281 
282         protected override void OnLostFocus(EventArgs e)
283         {
284             base.OnLostFocus(e);
285             if (handle != IntPtr.Zero)
286             {
287                 MiniblinkPInvoke.wkeKillFocus(handle);
288             }
289         }
290 
291         protected override void OnPreviewKeyDown(PreviewKeyDownEventArgs e)
292         {
293             base.OnPreviewKeyDown(e);
294             switch (e.KeyCode)
295             {
296                 case Keys.Down:
297                 case Keys.Up:
298                 case Keys.Left:
299                 case Keys.Right:
300                 case Keys.Tab:
301                     e.IsInputKey = true;
302                     break;
303             }
304         }
305         private static uint GetMouseFlags(MouseEventArgs e)
306         {
307             uint flags = 0;
308             if (e.Button == MouseButtons.Left)
309             {
310                 flags = flags | (uint)MiniblinkPInvoke.wkeMouseFlags.WKE_LBUTTON;
311             }
312             if (e.Button == MouseButtons.Middle)
313             {
314                 flags = flags | (uint)MiniblinkPInvoke.wkeMouseFlags.WKE_MBUTTON;
315             }
316             if (e.Button == MouseButtons.Right)
317             {
318                 flags = flags | (uint)MiniblinkPInvoke.wkeMouseFlags.WKE_RBUTTON;
319             }
320             if (Control.ModifierKeys == Keys.Control)
321             {
322                 flags = flags | (uint)MiniblinkPInvoke.wkeMouseFlags.WKE_CONTROL;
323             }
324             if (Control.ModifierKeys == Keys.Shift)
325             {
326                 flags = flags | (uint)MiniblinkPInvoke.wkeMouseFlags.WKE_SHIFT;
327             }
328             return flags;
329         }
330 
331 
332         protected override void Dispose(bool disposing)
333         {
334             base.Dispose(disposing);
335             if (handle != IntPtr.Zero)
336             {//资源释放
337                 MiniblinkPInvoke.wkeDestroyWebView(handle);
338                 handle = IntPtr.Zero;
339             }
340             if (bits != IntPtr.Zero)
341             {
342                 Marshal.FreeHGlobal(bits);
343                 bits = IntPtr.Zero;
344             }
345         }
346 
347         public event EventHandler UrlChanged;
348 
349         protected virtual void OnUrlChanged(EventArgs e)
350         {
351             if (UrlChanged != null)
352             {
353                 UrlChanged(this, e);
354             }
355         }
356 
357     }
358 }

代码写好之后,生成一下,工具箱里就有控件了,然后拖到界面,设置Url,运行就有效果了

如果你想偷懒,要更完整的功能你可以看看 DSKin

DSkin已经封装好 Html构建桌面UI的快捷开发方式,资源内嵌,C#和JS互相调用,无需写麻烦的参数数据转换,通过Vue实现C#属性和页面双向绑定,页面和C#类对应等等,就像WebForm开发。 窗体阴影、系统按钮那些都是Html+CSS定义的

原文地址:https://www.cnblogs.com/dskin/p/8664912.html