Windows Form 加入载入动画


在 Windows Forms 应用程式中加入「载入动画」并不简单:解决「UI 执行绪阻塞」问题。以下是说明、实作步骤及范例程式码。

什么是「UI 执行绪阻塞」?

当一个表单(Form)取得操作焦点时,其他在背景运行的表单将暂停动作。因此,当载入动画出现时,必须另开执行绪在背景中执行接着要显示的新表单,才能让动画持续播放。

主执行绪的控制权问题

这时又产生了一个问题...由于新表单是透过另一个执行绪开启的,当新表单显示时,该执行绪会取得控制权成为主执行绪,而负责动画的执行绪则失去控制权,使得关闭动画的操作无法顺利执行。因此,必须将「关闭动画」的指令交由处理新表单的执行绪来执行。

完整实作流程

  • 以对话框的形式显示载入动画表单,锁住其他表单并强制使用者等待。
  • 在背景执行绪中初始化新表单,然后关闭动画并显示新表单。
  • 等待背景执行绪完成操作。
  • 借由使用 async / await 关键字,能用最少的程式码完成以上流程。

    范例程式 Sample Code

    表单及元件配置:

  • 建立 3 张 Windows Form:Form1、Form2及FormLoading。
  • 在 FormLoading 表单中加入一个 PictureBox 元件,放入 loading.gif 作为载入动画(GIF 来源:GIFER 网站:https://gifer.com/en/ZKZg
  • 在 Form1 放置 1 个 button,name 属性为「btnOpenForm2」, 显示文字是「Open Form2」。
  • Form2 放置 1 个 Lable 元件显示文字「load complete」,并在 Form2 初始化时等待 5 秒模拟载入延迟。
  • 在 btnOpenForm2 的 Click 事件中,加入程式码以背景执行绪开启新表单,并控制动画的关闭与新表单的显示。
  • Form1.cs

    private async void btnOpenForm2_Click(object sender, EventArgs e)
    {
    using (var formLoading = new FormLoading())
    {
    // 在背景执行绪初始化 Form2,完成后关闭动画再显示 Form2
    var loadForm2Task = Task.Run(() =>
    {
    var form2 = new Form2();
    formLoading.DialogResult = DialogResult.OK;
    form2.ShowDialog();
    });

    // 以Dialog显示loading form,锁住其他的表单强迫使用者等待
    formLoading.ShowDialog();

    // 等待 Form2 完成初始化并显示
    await loadForm2Task;
    }
    }

    Form2.cs

    public Form2()
    {
    InitializeComponent();
    LoadData();
    }

    private void LoadData()
    {
    // 模拟载入时间 (非同步等待 5 秒)
    Thread.Sleep(5000);

    Label lbl = new Label { Text = "loading complete", AutoSize = true };
    this.Controls.Add(lbl);
    }

    FormLoading.cs

    public FormLoading()
    {
    InitializeComponent();
    this.StartPosition = FormStartPosition.CenterParent;
    this.FormBorderStyle = FormBorderStyle.None;
    }

    本文同步发表至我的Blog