WinForm——软件加载读条界面卡死问题
- 前言
- 一、问题现象
- 二、测试部分代码
- 1.Loading窗体
- 2.加载代码Program处
- 三、分析原因
- 四、解决方案代码
- 1.Loading窗体
- 2.加载代码Program处
前言
在制作软件开启界面,读条加载时,在Program中new了个Loading窗体,却发现窗体显示但是界面中的控件显示却不跟随改变,甚至出现卡死的情况,故分析产生的原因,并找到解决方案。
一、问题现象
正常情况:
状况一:(通过Form中自己写的Set去设置文本的)
状况二:(通过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处
代码如下:
/// <summary>
/// 应用程序的主入口点。
/// </summary>
[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);
}
}