[C#] 使用 Invoke & BeginInvoke 的元件調用方式,讓程式執行效率更順暢! -JY. MN 軟實力


介紹

  以往的程式在進行中,需要 UI 元件更新時,往往都是直接調用控制元件進行屬性更新。在多執行緒的專案上,這樣的調用方式是錯誤的。Inovke 與 BeginInvoke 主要功能是在執行緒中使用委派進行調用 UI 控制元件,進行元件屬性的跟動,其中也包含控制元件的數據更新。

程式中使用 ProgressBar (兩個) 、Button (兩個) 控制元件來做簡單的示範:



以上是執行前的初始畫面與執行中的結果畫面。

示範

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace EX_Invoke_BeginInvoke
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }
        public delegate void MyInvoke(ProgressBar pb);

        private void Update_progressBar1(ProgressBar pb)
        {
            // 執行PerformStep()函式
            pb.PerformStep();
        }
        private void btn_Invoke_Click(object sender, EventArgs e)
        {
            MyInvoke mi = new MyInvoke(Update_progressBar1);

            // 顯示進度條控制元件
            progressBar1.Visible = true;
            // 設定進度條最小值
            progressBar1.Minimum = 1;
            // 設定進度條最大值
            progressBar1.Maximum = 100;
            // 設定進度條初始值
            progressBar1.Value = 1;
            // 設定進度條每次增加的步長
            progressBar1.Step = 1;

            for (int i = 0; i < 100; i++)
            {
                Thread.Sleep(300);
                this.Invoke(mi, new object[] { progressBar1 });
            }
        }

        private void btn_BeginInvoke_Click(object sender, EventArgs e)
        {
            MyInvoke mi = new MyInvoke(Update_progressBar1);

            // 顯示進度條控制元件
            progressBar1.Visible = true;
            // 設定進度條最小值
            progressBar1.Minimum = 1;
            // 設定進度條最大值
            progressBar1.Maximum = 100;
            // 設定進度條初始值
            progressBar1.Value = 1;
            // 設定進度條每次增加的步長
            progressBar1.Step = 1;

            for (int i = 0; i < 100; i++)
            {
                Thread.Sleep(300);
                this.BeginInvoke(mi, new object[] { progressBar2 });
            }
        }
    }
}


說明


        在範例程式中,先創立一個委派可調用工具。後續創立兩個 Button Click 事件,裡面分別使用 Invoke 與 BeginInvoke 這兩種調用方式:
  1. Invoke: 程式碼在跑完 this.Invoke(mi, ****) 後會直接進 Update_progressBar1(ProgressBar) 方法內進行 ProgressBar 進度條更新。
  2. BeginInvoke: 會等到 ButtonClick 跑完後才會進 Update_progressBar1(ProgressBar) 方法進行 ProgressBar  進度條更新。
        

結論

  這兩者的差異在於更新控制元件的時序不同,白話說就是 Invoke 會立即更新,BeginInvoke 會排序更新(比較慢)。這樣做的好處在於預防執行序衝突的狀況產生,往往在大型專案上一些不明錯誤都會發生在這種小地方上,請各位碼農多多注意了!

留言

熱門文章