WinForm——软件加载读条界面卡死问题

WinForm——软件加载读条界面卡死问题

  • 前言
  • 一、问题现象
  • 二、测试部分代码
    • 1.Loading窗体
    • 2.加载代码Program处
  • 三、分析原因
  • 四、解决方案代码
    • 1.Loading窗体
    • 2.加载代码Program处


前言

在制作软件开启界面,读条加载时,在Program中new了个Loading窗体,却发现窗体显示但是界面中的控件显示却不跟随改变,甚至出现卡死的情况,故分析产生的原因,并找到解决方案。


一、问题现象

正常情况:
在这里插入图片描述

状况一:(通过Form中自己写的Set去设置文本的)
WinForm——软件加载读条界面卡死问题_第1张图片
状况二:(通过Form定时器自动循环去写文本的)
在这里插入图片描述
状况三:(通过Form中自定义线程循环去写文本的)
在这里插入图片描述

二、测试部分代码

1.Loading窗体

代码如下:

        public FrmLoading()
        {
            InitializeComponent();
            this.StartPosition = FormStartPosition.CenterScreen;
        }


        public void SetPercentVal(int val,string message)
        {
            this.Invoke(new Action(() =>
            {
                this.SuspendLayout();
                pgb_1.Value = val;
                //lb_Percent.Text = "%" + pgb_1.Value;
                //lb_Message.Text = message;
                this.ResumeLayout();
            }));
        }

        private void FrmLoading_Load(object sender, EventArgs e)
        {
            Thread thread = new Thread(a);
            thread.IsBackground = true;
            thread.Start();

            //this.DoubleBuffered = true;
            timer1.Enabled = true;
        }

        void a() 
        {
            while (true)
            {
                this.Invoke(new Action(() =>
                {
                    lb_Percent.Text = "%" + pgb_1.Value;

                }));

            }
            //lb_Message.Text = Meaagae;

        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            //if (pgb_1.Value == 100)
            //{
            //    if (this.InvokeRequired)
            //    {
            //        this.Invoke((Action)this.Close);
            //    }
            //    else
            //    {
            //        this.Close();
            //    }
            //}
            //else
            //{
            //    lb_Percent.Text = "%" + pgb_1.Value;
            //    //lb_Message.Text = Meaagae;
            //}
        }

2.加载代码Program处

代码如下:

        /// 
        /// 应用程序的主入口点。
        /// 
        [STAThread]
        static void Main()
        {
            LogHelper.WriteInfo("------------------------------------------------");
            LogHelper.WriteInfo("软件启动。");
            LogHelper.WriteInfo("------------------------------------------------");

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            
            Global_Value.G_LoadingFrm = new UI_Frm.FrmLoading();
            Global_Value.G_LoadingFrm.Show();

            while (Global_Value.G_LoadingFrm == null || !Global_Value.G_LoadingFrm.Visible)
            {
                System.Threading.Thread.Sleep(100);
            }

            //初始化
            Global_Method.Ini();

            Global_Value.G_LoadingFrm.SetPercentVal(90, "初始化界面");

            Global_Value.G_MainFrm = new FrmMain();
            Global_Value.G_MainFrm.Visible = true;

            Global_Value.G_LoadingFrm.SetPercentVal(100, "加载完成");
			Global_Value.G_LoadingFrm.Close();
			
            Application.Run(Global_Value.G_MainFrm);
        }


三、分析原因

以Timer版本的举例,在 C# 的 Windows 窗体应用程序中,Timer 组件的 Tick 事件会在 UI 线程上触发。这意味着,当调用 Application.Run 方法启动主消息循环后,UI 线程开始处理窗体和控件的消息,并触发 Timer 组件的 Tick 事件。
如果在 Program 类中的 Main 方法中先创建窗体并启动定时器,然后再调用 Application.Run,由于主消息循环尚未开始,UI 线程不会触发 Tick 事件,因此事件处理程序不会执行。
其他两种情况也都相类似,也都是未启用消息循环导致,文本不跟新卡死的情况。故有如下的解决方案。

四、解决方案代码

再Loading界面开始时就开启消息循环,并在其结束后关闭。
具体优化代码(部分)如下:

1.Loading窗体

代码如下:

    public partial class FrmLoading : Form
    {
        public FrmLoading()
        {
            InitializeComponent();
            this.StartPosition = FormStartPosition.CenterScreen;
        }


        public void SetPercentVal(int val,string message)
        {
            this.Invoke(new Action(() =>
            {
                pgb_1.Value = val;
                lb_Percent.Text = "%" + pgb_1.Value;
                lb_Message.Text = message;
            }));
        }

        private void FrmLoading_Load(object sender, EventArgs e)
        {
            timer1.Enabled = true;
        }


        private void timer1_Tick(object sender, EventArgs e)
        {
            if (pgb_1.Value == 100)
            {
                if (this.InvokeRequired)
                {
                    this.Invoke((Action)this.Close);
                }
                else
                {
                    this.Close();
                }
            }
        }
    }

2.加载代码Program处

代码如下:

        static void Main()
        {
            LogHelper.WriteInfo("------------------------------------------------");
            LogHelper.WriteInfo("软件启动。");
            LogHelper.WriteInfo("------------------------------------------------");

            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);

            var loadingFormThread = new System.Threading.Thread(ShowLoadingForm); // 创建加载界面线程
            loadingFormThread.Start(); // 启动加载界面线程

            while (Global_Value.G_LoadingFrm == null || !Global_Value.G_LoadingFrm.Visible)
            {
                System.Threading.Thread.Sleep(100);
            }

            //初始化
            Global_Method.Ini();


            Global_Value.G_LoadingFrm.SetPercentVal(90, "初始化界面");

            Global_Value.G_MainFrm = new FrmMain();
            Global_Value.G_MainFrm.Visible = true;

            Global_Value.G_LoadingFrm.SetPercentVal(100, "加载完成");

            loadingFormThread.Join();//等待加载界面结束
            Application.Run(Global_Value.G_MainFrm);
        }

        private static void ShowLoadingForm()
        {
            Global_Value.G_LoadingFrm = new UI_Frm.FrmLoading();
            Application.Run(Global_Value.G_LoadingFrm);
        }
    }

你可能感兴趣的:(#,C#Winform,前端,c#)