DataGridView右鍵菜單自定義顯示及隱藏列

来源:https://www.cnblogs.com/atomy/archive/2019/11/12/11812458.html
-Advertisement-
Play Games

WinForm程式中表單的列可自定義顯示及隱藏,是一種常見的功能,對於用戶體驗來說是非常好的。筆者經過一段時間的摸索,終於實現了自己想要的功能及效果,現記錄一下過程: 1、新建一個自定義控制項,命名為:PopupMenuControl。 2、在PopupMenuControl.Designet文件中的 ...


    WinForm程式中表單的列可自定義顯示及隱藏,是一種常見的功能,對於用戶體驗來說是非常好的。筆者經過一段時間的摸索,終於實現了自己想要的功能及效果,現記錄一下過程:

    1、新建一個自定義控制項,命名為:PopupMenuControl。

    2、在PopupMenuControl.Designet文件中的InitializeComponent()方法下麵,註冊以下事件:

    this.Paint += new System.Windows.Forms.PaintEventHandler(this.PopupMenuControl_Paint);
    this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.PopupMenuControl_MouseDown);
    this.MouseMove += new System.Windows.Forms.MouseEventHandler(this.PopupMenuControl_MouseMove);

    3、PopupMenuControl的代碼:

    public partial class PopupMenuControl : UserControl
    {
        public delegate void CheckedChanged(int hitIndex, bool isChecked);  //勾選改變委托
        public event CheckedChanged CheckedChangedEvent;                    //勾選改變事件
        PopupMenuHelper popupMenuHelper = null;                             //菜單幫助類,主要負責菜單繪製。

        public PopupMenuControl()
        {
            InitializeComponent();
        }

        public void Initialize(DataGridView dgvTarget)
        {
            //菜單幫助類實例化
            popupMenuHelper = new PopupMenuHelper();
            //將列標題添加到items
            foreach (DataGridViewColumn column in dgvTarget.Columns)
            {
                popupMenuHelper.AddItem(column.HeaderText, column.Visible);
            }
            //菜單繪製
            popupMenuHelper.Prepare(CreateGraphics());
            Width = popupMenuHelper.Width;
            Height = popupMenuHelper.Height;
        }

        /// <summary>
        /// 繪製
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PopupMenuControl_Paint(object sender, PaintEventArgs e)
        {
            popupMenuHelper.Draw(e.Graphics);
        }

        /// <summary>
        /// 滑鼠移過
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PopupMenuControl_MouseMove(object sender, MouseEventArgs e)
        {
            if (popupMenuHelper.IsMouseMove(e.X, e.Y))
            {
                popupMenuHelper.Draw(CreateGraphics());
            }
        }

        /// <summary>
        /// 滑鼠按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void PopupMenuControl_MouseDown(object sender, MouseEventArgs e)
        {
            if (popupMenuHelper.IsMouseDown(e.X, e.Y))
            {
                int hitIndex = popupMenuHelper.HitIndex;
                if (hitIndex != -1)
                {
                    bool isChecked = popupMenuHelper.IsCheckedChange(hitIndex, CreateGraphics());
                    OnCheckedChanged(hitIndex, isChecked);
                }
            }
        }

        /// <summary>
        /// 勾選改變
        /// </summary>
        /// <param name="iIndex"></param>
        /// <param name="bChecked"></param>
        public virtual void OnCheckedChanged(int hitIndex, bool isChecked)
        {
            CheckedChangedEvent?.Invoke(hitIndex, isChecked);
        }
    }

    4、這上面涉及到一個PopupMenuHelper的幫助類,此幫助類主要是為PopupMenuControl控制項實現菜單繪製的功能,其代碼如下:

    class PopupMenuHelper
    {
        //變數
        private PopupMenuItem hotItem = null;                           //當前Item
        private List<PopupMenuItem> items = new List<PopupMenuItem>();  //Item集合
        private Bitmap bitmap;                                          //點陣圖
        private Graphics graphics;                                      //圖像
        private static readonly int BasicConst = 24;                    //Item:高度、Image寬度
        private static readonly int BasicGap = 3;                       //四周間距
        private static readonly int BasicRows = 3;                      //最大行數
        private static readonly int BasicSide = 10;                     //Item:CheckBox邊長(建議用偶數)
        private int totality = 1;                                       //分割總數
        private int[] eachWidth = null;                                 //各個寬度

        //屬性
        public int Width { get { return bitmap.Width; } }               //寬度
        public int Height { get { return bitmap.Height; } }             //高度

        //PopupMenuItem類
        private class PopupMenuItem
        {
            //屬性
            public string ItemText { get; set; }                        //Item文本
            public bool IsChecked { get; set; }                         //勾選狀態

            //構造函數
            public PopupMenuItem(string itemText) : this(itemText, false)
            {
            }
            public PopupMenuItem(string itemText, bool isChecked)
            {
                ItemText = itemText;
                IsChecked = isChecked;
            }
        }

        //無參構造函數
        public PopupMenuHelper()
        {
        }

        /// <summary>
        /// 被點擊Item的Index
        /// </summary>
        public int HitIndex
        {
            get
            {
                return items.IndexOf(hotItem);
            }
        }

        /// <summary>
        /// 勾選改變狀態
        /// </summary>
        /// <param name="hitIndex">被點擊Item的Index</param>
        /// <param name="g">圖像</param>
        /// <returns></returns>
        public bool IsCheckedChange(int hitIndex, Graphics g)
        {
            items[hitIndex].IsChecked = !items[hitIndex].IsChecked;
            Draw(g);
            return items[hitIndex].IsChecked;
        }

        /// <summary>
        /// 添加Item
        /// </summary>
        /// <param name="itemText">Item文本</param>
        /// <param name="isChecked">Item勾選狀態</param>
        public void AddItem(string itemText, bool isChecked)
        {
            items.Add(new PopupMenuItem(itemText, isChecked));
        }

        /// <summary>
        /// 繪製菜單準備
        /// </summary>
        /// <param name="g">圖像</param>
        public void Prepare(Graphics g)
        {
            //獲取菜單的寬度及高度
            totality = (int)Math.Ceiling((double)items.Count / BasicRows);
            eachWidth = new int[totality];
            int totalWidth = 0, totalHeight = 0;
            double maxTextWidth = 0;
            if (totality == 1)
            {
                totalHeight = items.Count * BasicConst + 2 * BasicGap;
                foreach (PopupMenuItem item in items)
                {
                    //SizeF:存儲有序浮點數對,通常為矩形的寬度和高度。
                    SizeF sizeF = g.MeasureString(item.ItemText, SystemInformation.MenuFont);
                    maxTextWidth = Math.Max(maxTextWidth, sizeF.Width);
                }
                totalWidth = (int)Math.Ceiling((double)maxTextWidth) + BasicConst + 2 * BasicGap;
                eachWidth[0] = (int)Math.Ceiling((double)maxTextWidth) + BasicConst;
            }
            else
            {
                totalHeight = BasicRows * BasicConst + 2 * BasicGap;
                int rows = 0, cols = 1;
                foreach (PopupMenuItem item in items)
                {
                    rows++;
                    //SizeF:存儲有序浮點數對,通常為矩形的寬度和高度。
                    SizeF sizeF = g.MeasureString(item.ItemText, SystemInformation.MenuFont);
                    maxTextWidth = Math.Max(maxTextWidth, sizeF.Width);
                    if (cols < totality)
                    {
                        //1..[totality-1]列
                        if (rows == BasicRows)
                        {
                            totalWidth += (int)Math.Ceiling((double)maxTextWidth) + BasicConst;
                            eachWidth[cols - 1] = (int)Math.Ceiling((double)maxTextWidth) + BasicConst;
                            maxTextWidth = 0;
                            cols++;
                            rows = 0;
                        }
                    }
                    else
                    {
                        //totality列
                        if ((cols - 1) * BasicRows + rows == items.Count)
                        {
                            totalWidth += (int)Math.Ceiling((double)maxTextWidth) + BasicConst + 2 * BasicGap;
                            eachWidth[cols - 1] = (int)Math.Ceiling((double)maxTextWidth) + BasicConst;
                        }
                    }
                }
            }
            //圖像初始化
            bitmap = new Bitmap(totalWidth, totalHeight);
            graphics = Graphics.FromImage(bitmap);
        }

        /// <summary>
        /// 繪製菜單
        /// </summary>
        /// <param name="g"></param>
        public void Draw(Graphics g)
        {
            Rectangle area = new Rectangle(0, 0, bitmap.Width, bitmap.Height);
            graphics.Clear(SystemColors.Menu);
            DrawBackground(graphics, area);
            DrawItems(graphics);
            g.DrawImage(bitmap, area, area, GraphicsUnit.Pixel);
        }

        /// <summary>
        /// 繪製菜單背景
        /// </summary>
        /// <param name="g"></param>
        /// <param name="area"></param>
        private void DrawBackground(Graphics g, Rectangle area)
        {
            //描邊
            using (Pen borderPen = new Pen(Color.FromArgb(112, 112, 112)))
                g.DrawRectangle(borderPen, area);

            //Image及Text
            int left = BasicGap, top = BasicGap;
            if (totality == 1)
            {
                Rectangle imageArea = new Rectangle(left, top, BasicConst, items.Count * BasicConst);
                using (Brush backBrush = new SolidBrush(Color.FromArgb(240, 240, 240)))
                    g.FillRectangle(backBrush, imageArea);

                Rectangle textArea = new Rectangle(left + BasicConst, top, eachWidth[0], items.Count * BasicConst);
                using (Brush backBrush = new SolidBrush(Color.FromArgb(255, 255, 255)))
                    g.FillRectangle(backBrush, textArea);
            }
            else
            {
                for (int i = 0; i < totality; i++)
                {
                    Rectangle imageArea = new Rectangle(left, top, BasicConst, BasicRows * BasicConst);
                    using (Brush backBrush = new SolidBrush(Color.FromArgb(240, 240, 240)))
                        g.FillRectangle(backBrush, imageArea);

                    Rectangle textArea = new Rectangle(left + BasicConst, top, eachWidth[i], BasicRows * BasicConst);
                    using (Brush backBrush = new SolidBrush(Color.FromArgb(255, 255, 255)))
                        g.FillRectangle(backBrush, textArea);

                    left += eachWidth[i];
                }
            }
        }

        /// <summary>
        /// 繪製所有菜單Item
        /// </summary>
        /// <param name="g">圖像</param>
        private void DrawItems(Graphics g)
        {
            int left = BasicGap, top = BasicGap;
            int rows = 0, cols = 1;
            foreach (PopupMenuItem item in items)
            {
                if (totality == 1)
                {
                    DrawSingleItem(g, left, ref top, eachWidth[0], item, item == hotItem);
                }
                else
                {
                    rows++;
                    DrawSingleItem(g, left, ref top, eachWidth[cols - 1], item, item == hotItem);
                    //1..[totality-1]列
                    if (rows % BasicRows == 0)
                    {
                        left += eachWidth[cols - 1];
                        top = BasicGap;
                        cols++;
                        rows = 0;
                    }
                }
            }
        }

        /// <summary>
        /// 繪製單個菜單Item
        /// </summary>
        /// <param name="g">圖像</param>
        /// <param name="top">圖像Top</param>
        /// <param name="item">菜單Item</param>
        /// <param name="isHotItem">是否為當前菜單Item</param>
        private void DrawSingleItem(Graphics g, int left, ref int top,int width, PopupMenuItem item, bool isHotItem)
        {
            //Item區域
            Rectangle drawRect = new Rectangle(left, top, width, BasicConst);
            top += BasicConst;

            //Text區域
            Rectangle itemTextArea = new Rectangle
                (
                    drawRect.Left + BasicConst,
                    drawRect.Top,
                    drawRect.Width - BasicConst,
                    drawRect.Height
                );

            //背景色及描邊色
            if (isHotItem)
            {
                //HotItem
                Rectangle hotItemArea = new Rectangle(drawRect.Left, drawRect.Top, drawRect.Width, drawRect.Height);
                using (SolidBrush backBrush = new SolidBrush(Color.FromArgb(214, 235, 255)))
                    g.FillRectangle(backBrush, hotItemArea);
                using (Pen borderPen = new Pen(Color.FromArgb(51, 153, 255)))
                    g.DrawRectangle(borderPen, hotItemArea);
            }

            //Text處理
            StringFormat itemTextFormat = new StringFormat();
            //NoClip:允許顯示字形符號的伸出部分和延伸到矩形外的未換行文本。
            //NoWrap:在矩形內設置格式時,禁用自動換行功能。
            itemTextFormat.FormatFlags = StringFormatFlags.NoClip | StringFormatFlags.NoWrap;
            //Near:指定文本靠近佈局對齊。
            itemTextFormat.Alignment = StringAlignment.Near;
            //Center:指定文本在佈局矩形中居中對齊(呃,感覺不是很垂直居中,偏上了一些)。
            itemTextFormat.LineAlignment = StringAlignment.Center;
            //Show:顯示熱鍵首碼。
            itemTextFormat.HotkeyPrefix = HotkeyPrefix.Show;

            SolidBrush textBrush = new SolidBrush(SystemColors.MenuText);
            g.DrawString(item.ItemText, SystemInformation.MenuFont, textBrush, itemTextArea, itemTextFormat);

            //Checkbox處理
            if (item.IsChecked)
            {
                int checkBoxGap = (int)((drawRect.Height - BasicSide) / 2);
                int checkBoxLeft = drawRect.Left + checkBoxGap;
                int checkBoxTop = drawRect.Top + checkBoxGap;

                //將checkBoxArea的Top減1,與文本的對齊效果稍微好一些。
                Rectangle checkBoxArea = new Rectangle(checkBoxLeft, checkBoxTop - 1, BasicSide, BasicSide);
                using (Brush checkBoxBrush = new SolidBrush(Color.FromArgb(214, 235, 255)))
                    g.FillRectangle(checkBoxBrush, checkBoxArea);
                using (Pen checkBoxPen = new Pen(Color.FromArgb(51, 153, 255)))
                    g.DrawRectangle(checkBoxPen, checkBoxArea);

                using (Pen checkBoxTick = new Pen(Color.FromArgb(51, 153, 255)))
                {
                    g.DrawLine(checkBoxTick, new Point(checkBoxLeft, checkBoxTop - 1 + (int)(BasicSide / 2)), new Point(checkBoxLeft + (int)(BasicSide / 2), checkBoxTop - 1 + BasicSide));
                    g.DrawLine(checkBoxTick, new Point(checkBoxLeft + (int)(BasicSide / 2), checkBoxTop - 1 + BasicSide), new Point(checkBoxLeft + BasicSide + BasicGap, checkBoxTop - 1 - BasicGap));
                }
            }
        }

        /// <summary>
        /// 點擊測試
        /// </summary>
        /// <param name="X">X坐標</param>
        /// <param name="Y">Y坐標</param>
        /// <returns></returns>
        private PopupMenuItem HitTest(int X, int Y)
        {
            if (X < 0 || X > Width || Y < 0 || Y > Height)
            {
                return null;
            }

            int left = BasicGap, top = BasicGap;
            int rows = 0, cols = 1;
            foreach (PopupMenuItem item in items)
            {
                if (totality == 1)
                {
                    rows++;
                    if (X > left && X < left + eachWidth[0] && Y > top + (rows - 1) * BasicConst && Y < top + rows * BasicConst)
                    {
                        return item;
                    }
                }
                else
                {
                    rows++;
                    if (X > left && X < left + eachWidth[cols - 1] && Y > top + (rows - 1) * BasicConst && Y < top + rows * BasicConst)
                    {
                        return item;
                    }
                    //1..[totality-1]列
                    if (rows % BasicRows == 0)
                    {
                        left += eachWidth[cols - 1];
                        top = BasicGap;
                        cols++;
                        rows = 0;
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// 是否是滑鼠移過
        /// </summary>
        /// <param name="X">X坐標</param>
        /// <param name="Y">Y坐標</param>
        /// <returns></returns>
        public bool IsMouseMove(int X, int Y)
        {
            PopupMenuItem popupMenuItem = HitTest(X, Y);
            if (popupMenuItem != hotItem)
            {
                hotItem = popupMenuItem;
                return true;
            }
            else
            {
                return false;
            }
        }

        /// <summary>
        /// 是否是滑鼠按下
        /// </summary>
        /// <param name="X">X坐標</param>
        /// <param name="Y">Y坐標</param>
        /// <returns></returns>
        public bool IsMouseDown(int X, int Y)
        {
            PopupMenuItem popupMenuItem = HitTest(X, Y);
            return popupMenuItem != null;
        }
    }

    這個類實現了多菜單頁面的功能:即如果DataGridView欄位非常的多,可通過產生多列菜單來顯示,程式是通過BasicRows變數來控制。

    5、新建一個DataGridViewColumnSelector類,此類的功能主要是銜接DataGridView與PopupMenuControl,其代碼如下:

/// <summary>
    /// DataGridView右鍵菜單自定義顯示及隱藏列
    /// </summary>
    class DataGridViewColumnSelector
    {
        private DataGridView dgvTarget = null;                      //待處理的DataGridView對象
        private ToolStripDropDown dropDown;                         //用於載入PopupMenu控制項
        PopupMenuControl popupMenuControl = new PopupMenuControl(); //PopupMenu控制項

        //無參構造函數
        public DataGridViewColumnSelector()
        {
            //註冊PopupMenu控制項事件
            popupMenuControl.CheckedChangedEvent += new PopupMenuControl.CheckedChanged(OnCheckedChanged);
            //使用容器承載PopupMenu控制項(相當於容器類型的ToolStripItem)
            ToolStripControlHost controlHost = new ToolStripControlHost(popupMenuControl);
            controlHost.Padding = Padding.Empty;
            controlHost.Margin = Padding.Empty;
            controlHost.AutoSize = false;
            //載入PopupMenu控制項
            dropDown = new ToolStripDropDown();
            dropDown.Padding = Padding.Empty;
            dropDown.AutoClose = true;
            dropDown.Items.Add(controlHost);
        }

        //有參構造函數
        public DataGridViewColumnSelector(DataGridView dataGridView) : this()
        {
            DataGridView = dataGridView;
        }

        //DataGridView屬性
        public DataGridView DataGridView
        {
            get { return dgvTarget; }
            set
            {
                //去除單元格點擊事件
                if (dgvTarget != null) { dgvTarget.CellMouseClick -= new DataGridViewCellMouseEventHandler(DataGridView_CellMouseClick); }
                dgvTarget = value;
                //註冊單元格點擊事件
                if (dgvTarget != null) { dgvTarget.CellMouseClick += new DataGridViewCellMouseEventHandler(DataGridView_CellMouseClick); }
            }
        }

        /// <summary>
        /// 右鍵點擊標題欄彈出菜單
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void DataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
        {
            if (e.Button == MouseButtons.Right && e.RowIndex == -1)
            {
                popupMenuControl.Initialize(dgvTarget);
                //將菜單顯示在游標位置
                dropDown.Show(Cursor.Position);
            }
        }

        /// <summary>
        /// 勾選事件執行方法
        /// </summary>
        /// <param name="hitIndex"></param>
        /// <param name="isCheck"></param>
        private void OnCheckedChanged(int hitIndex, bool isChecked)
        {
            dgvTarget.Columns[hitIndex].Visible = isChecked;
        }
    }

    6、以上這些,已經實現了全部的功能。下麵開始建一個WinForm程式來測試結果,為方便測試將DataGridView的數據源由xml文件讀取。

          從SQL Server資料庫隨便找張數據表生成XML,文件保存為Test.xml。(請將Test.xml文件拷貝到Debug文件夾下麵)

SELECT TOP 10 MO_NO,MRP_NO,QTY,BIL_NO 
FROM MF_MO 
WHERE MO_DD='2019-11-07' 
ORDER BY MO_NO 
FOR XML PATH ('Category'),TYPE,ROOT('DocumentElement')

    7、新建一個WinForm程式,命名為Main,並拖入一個DataGridView控制項,Main_Load方法如下:

        private void Main_Load(object sender, EventArgs e)
        {
            try
            {
                //xml文件路徑
                string path = @"Test.xml";
                //讀取文件
                DataSet ds = new DataSet();
                if (File.Exists(path))
                {
                    ds.ReadXml(path);
                }
                dataGridView1.DataSource = ds.Tables.Count > 0 ? ds.Tables[0] : null;
                //加工dataGridView1
                #region 加列標題測試
                dataGridView1.Columns[0].HeaderText = "制令單號";
                dataGridView1.Columns[1].HeaderText = "成品編號";
                dataGridView1.Columns[2].HeaderText = "生產數量";
                dataGridView1.Columns[3].HeaderText = "來源單號";
                #endregion
                DataGridViewColumnSelector columnSelector = new DataGridViewColumnSelector(dataGridView1);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
        }

    8、執行程式,在任意DataGridView標題欄右擊,即可彈出菜單:

 

    好了,分享就到此結束了,希望對有此需要的人有一些幫助。

 


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

-Advertisement-
Play Games
更多相關文章
  • 入門python一切都感覺到那麼簡單,從來沒有想過人生還可以有這麼美好的待遇,這一切都是因為接觸了python才讓我感到生活原來一切又充滿了希望 ...
  • jdk: 解壓: tar zxvf jdk-8u144-linux-x64.tar.gz 執行:vi /etc/profile export JAVA_HOME=/usr/local/jdk1.8.0_201 export CLASSPATH=$JAVA_HOME/lib export PATH=$ ...
  • Day1 考的不是很好,T1T2沒區分度,T3想的太少,考試後期幾乎都是在摸魚,bitset亂搞也不敢打,只拿到了35分,跟前面的差距很大 A. 最大或 標簽: 二進位+貪心 題解: 首先x,y中一定有一個是R,考慮L的取值:對於每一位分為x中有沒有討論: 1>有 如果這一位不加以後全加可以>=L則 ...
  • Scrapy.http.Request 自動去重,根據url的哈希值,進行去重 屬性 meta(dict) 在不同的請求之間傳遞數據,dict priority(int) 此請求的優先順序(預設為0) dont_filter(boolean) 關閉自動去重 errback(callable) 在處理請 ...
  • 一、環境準備 1. jdk1.8.1 做java開發的這個應該能自己找到 2.gradle-4.9 https://services.gradle.org/distributions/ 沒用過gradle的同學可以將其理解為類似於maven的包管理工具,這裡下載gradle-4.9-bin.zip, ...
  • 本文源碼: "GitHub·點這裡" || "GitEE·點這裡" 一、生活場景 1、場景描述 在公司的日常安排中,通常劃分多個部門,每個部門又會分為不同的小組,部門經理的一項核心工作就是協調部門小組之間的工作,例如開發小組,產品小組,小組的需求統一彙總到經理,經理統一安排和協調。 2、場景圖解 3 ...
  • 什麼是ThreadLocal ThreadLocal有點類似於Map類型的數據變數。ThreadLocal類型的變數每個線程都有自己的一個副本,某個線程對這個變數的修改不會影響其他線程副本的值。需要註意的是一個ThreadLocal變數,其中只能set一個值。 線上程1中初始化了一個ThreadLo ...
  • C/C++文件 C/C++程式文件包括 .h .c .hpp .cpp,其中源文件(.c .cpp)是基本的編譯單元,頭文件(.h .hpp)不會被編譯器編譯。 C/C++項目構建(build)過程,分為以下幾個步驟 預處理 → 編譯 → 鏈接。 預編譯 預編譯的過程可以理解為編譯器(實際上是預處理 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...