c# 问题小结
最近做项目,遇到的问题蛮多的额,各种零零碎碎的问题一大箩筐,趁今天有闲暇时间,总结一下这几周遇到的问题。
一、Thread类的使用
①线程存在多种状态,有时在执行一些操作时,我们需要判断线程的状态,然后在执行相应的操作。
原图出处:http://blog.csdn.net/wangchongcy/article/details/7219880
例如线程当前的状态为Running,此时我们执行一些操作需要挂起线程,就要判断线程的状态是不是Running状态,
如果在创建线程时,设置MyThread.IsBackground=true.
然后判断线程状态时,使用if(MyThread.ThreadState==ThreadState.Running),返回值为false。
因为此时线程的状态为IsBackground。
正确的做法如下:
if ((MyThread.ThreadState & ThreadState.Running) == ThreadState.Running)
{
MyThread.Suspend();
}
msdn中有详细解释,ThreadState是枚举类型,它允许按位运算组合其变量。
例如测试线程是否在运行:
if (myThread.ThreadState & (ThreadState.Stopped | ThreadState.Unstarted)) == 0)
成员名称 说明 值
Aborted 线程处于 Stopped状态中。 256
AbortRequested 已对线程调用了 Thread.Abort方法,但线程尚未收到试图终止它的挂起的 System.Threading.ThreadAbortException。 128
Background 线程正作为后台线程执行(相对于前台线程而言)。此状态可以通过设置Thread.IsBackground属性来控制。 4
Running 线程已启动,它未被阻塞,并且没有挂起的ThreadAbortException。 0
Stopped 线程已停止。 16
StopRequested 正在请求线程停止。这仅用于内部。 1
Suspended 线程已挂起。 64
SuspendRequested 正在请求线程挂起。 2
Unstarted 尚未对线程调用 Thread.Start方法。 8
WaitSleepJoin 由于调用 Wait、Sleep或 Join,线程已被阻塞。 32
②线程退出
一般情况下,当线程中的函数执行完之后,它会自动结束。
有时候,我们需要在while(1){ do something...}
c#中,使用thread.Abort()强制终止线程时,会抛出异常:hreadAbortException。
在《改善C#代码》一书中,有提到过一种做法(类似于设置bool变量):
创建 CancellationTokenSourcects = new CancellationTokenSource();
线程中执行的函数改为
while(true)
{
if( cts.Token.IsCancellationRequested)
{
return;
}
do something;
}
在必要退出线程的地方,调用cts.Cancel()函数即可,更深入的了解大家可以再交流。
二、Mdi子窗体相关问题
①子窗体不能重复打开,如果子窗体已经打开,则不再打开;否则是关闭子窗体,再重新打开子窗体。(前提:Mdi父窗体中只允许打开一个子窗体)
此时:父窗体的属性IsMdiContainer=true;
/*********************************判断是否为子窗口************************************/
public bool JudgeIsChildForm(string formNameStr)
{
bool blIChooseForm = false;
foreach (Form frm in Application.OpenForms)
{
if (formNameStr.Equals(frm.Name))
{
blIChooseForm = true;
}
}
return blIChooseForm;
}
/*******************************************窗口显示************************************/
public void ShowAnyFormInMain(string FormName)
{
bool blIsChooseForm = false;
blIsChooseForm = JudgeIsChildForm(FormName);
if (!blIsChooseForm)
{
foreach (Form frm in this.MdiChildren)
{
if (!frm.IsDisposed)
{
frm.Close();
}
}
switch (FormName)
{
case "ConnectEquipmentForm":
{
childForm = new ConnectEquipmentForm();
}
break;
...
default:
break;
}
if (childForm != null)
{
childForm.MdiParent = this;
childForm.ControlBox = true;
//childForm.FormBorderStyle = System.Windows.Forms.FormBorderStyle.Sizable;
childForm.Resize +=new EventHandler(ChildForm_Resize);
childForm.WindowState = this.WindowState;
childForm.MaximizeBox = false;
childForm.MinimizeBox = false;
childForm.StartPosition = FormStartPosition.Manual;//固定窗体的起始位置,否则子窗体每次启动的位置都有所不同。
childForm.Activate();
childForm.Show();
}
}
}
然后在按钮下只需要调用ShowAnyFormInMain("窗体名称");
②“无法访问一个已释放的窗体”
如上 ①中的做法,假如我们在一个button下打开了一个子窗体,然后再关闭这个子窗体。再按这个button再次打开子窗体,可能会遇到问题
“无法访问一个已释放的窗体”
这说明:子窗体的资源未及时释放,而又再次调用子窗体来做一些事。
例如我的程序中,按一个按钮,打开一个子窗体,而后有读取一些数据使用Invoke显示到子窗体界面上。
捕获异常“创建窗体句柄之前,不能在控件上调用Invoke或BeginInvoke”
当时我尝试了一些做法, // 防止在窗口句柄初始化之前就走到下面的代码
1) 防止在窗口句柄初始化之前就执行到下面的代码
while (!this.IsHandleCreated)
{
;
}
2).
if(!this.IsHandleCreated)
{
this.CreateHandle();
}
第一种方法出现了死等的情况;第二种方法捕获到异常:“无法访问一个已释放的窗体”。
大家可以看到此时我们使用了childForm来表示子窗体(我的程序中也是如此),在子窗体关闭时,childForm并未Close,这才是产生问题的根本原因。
因此在父窗体的Form_Closing事件中,要判断
if(childForm!=null)//在这里不关闭窗体,第二次打开子窗体时,系统无法访问到一个已经释放的窗体。
{
childForm.Close();
}
有必要的话,在new子窗体时,也加强判断:
if (childForm == null || childForm.IsDisposed)
{
childForm = new XXForm();
}
(End!)