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定义的



浙公网安备 33010602011771号