C# 封裝miniblink 使用HTML/CSS/JS來構建.Net 應用程式界面和簡易瀏覽器

来源:https://www.cnblogs.com/dskin/archive/2018/04/04/8664912.html
-Advertisement-
Play Games

MiniBlink的作者是 龍泉寺掃地僧 miniblink是什麼? (抄了一下 龍泉寺掃地僧 寫的簡潔) Miniblink是一個全新的、追求極致小巧的瀏覽器內核項目,其基於chromium最新版內核,去除了chromium所有多餘的部件,只保留最基本的排版引擎blink。Miniblink保持了 ...


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 	   

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 簡介 SourceTree 是一款擁有可視化界面的項目版本控制軟體,適用於git項目管理,同時它集成了 git flow 工作流程,對於不熟悉 git 命令的初學者來說,可以通過 SourceTree 快速學會使用 Git 和 git flow 來參與代碼版本管理和團隊協作開發。 問題 今日在全新的 ...
  • 最近由於工作需要,開始寫托管C++,由於C++11中的mutex,和future等類,托管C++不讓調用(報錯),所以自己實現了托管C++的線程鎖。 該類可確保當一個線程位於代碼的臨界區時,另一個線程不會進入該臨界區。 如果其他線程嘗試進入鎖定的代碼,則它將一直等待(即被阻止),直到該對象被釋放。 ...
  • 概述 UWP Community Toolkit 中有一個自適應的 GridView 控制項 - AdaptiveGridView,本篇我們結合代碼詳細講解 AdaptiveGridView 的實現。 AdaptiveGridView 控制項能夠以均勻分組的方式,讓一組列填充整個顯示空間,它可以對佈局和 ...
  • 大家好!我叫藍顏,我是一名大專生。這是我第一次接觸博客園,以後也會一直在。 在學校期間,參加技能大賽(物聯網),接觸到的C#。之後學校教務處要一個調課軟體, 於是我就小試牛刀試了試。當然了,這也是我第一次寫,途中遇到很多問題。竟然是調課 系統肯定會用到word,因為老師的課表都是用word成列出來的 ...
  • 在序言中,我們提到函數式編程的兩大特征:無副作用、函數是第一公民。現在,我們先來深入第一個特征:無副作用。 無副作用是通過引用透明(Referential transparency)來定義的。如果一個表達式滿足將它替換成它的值,而程式的行為不變,則稱這個表達式是引用透明的。 現在,我們不妨進行一個嘗 ...
  • 介紹asp.net core創建的列表模板頁面與一些佈局信息。 ...
  • 1、在Startup類的Configure方法,添加身份驗證的中間件AuthenticationMiddleware 2、在Startup類的ConfigureServices方法,添加Cookie驗證的服務,使用Cookies驗證體系, CookieAuthenticationDefaults.A ...
  • 前言 由於項目需求,需要將Excel中的數據進過一定轉換導入僅Oracle資料庫中。考慮到當Excel數據量較大時,迴圈Insert語句效率太低,故採用批量插入的方法。在插入操作運行時,會造成系統短暫的“卡死”現象。為了讓用戶知道插入的狀態,需要製作一個進度條來顯示插入的進度。 批量插入 項目中運用 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...