我有两个线程使用BeginInvoke方法将一些Windows窗体对象(面板和标签)可见性属性更改为false。问题是我不确定何时发生更改。我可以看到面板不存在(所以BeginInvoke方法有效)但是我的 if condition 检查可见性状态总是在第一次激活表单时返回 true 。
bool notVisible = false;
private void LunchMainScreen_Activated(object sender, EventArgs e) {
String CurrentSite = "";
List<DateTime> availableDates = new List<DateTime>();
// Get available dates
Thread availableDatesThread = new Thread(delegate() {
availableDates = LunchUserPreferences.GetUserAvailableDates();
changeObjVisible(notVisible, selectAvailabilityPanel);
changeObjVisible(notVisible, whenLbl);
}
});
availableDatesThread.Start();
// Get user current site
Thread checkSiteThread = new Thread(delegate() {
CurrentSite = LunchUserPreferences.GetUserSite();
changeObjVisible(notVisible, selectSitePanel);
changeObjVisible(notVisible, whereLbl);
}
updateText(CurrentSite, CurrentSiteSetLbl);
});
checkSiteThread.Start();
while (selectSitePanel.Visible == false && selectAvailabilityPanel.Visible == false) {
// it NEVER gets here, even though the panels are NOT visible when the program loads
WhoLunchTable.Visible = false;
WhoLunchTable.SuspendLayout();
listOfAvailableGroups.Clear();
WhoLunchTable.Controls.Clear();
WhoLunchTable.RowStyles.Clear();
PopulateTable();
WhoLunchTable.Visible = true;
WhoLunchTable.ResumeLayout();
break;
}
}
private delegate void changeObjVisibleDelegate(bool visibility, object obj);
private void changeObjVisible(bool visibility, object obj) {
if (this.InvokeRequired) {
this.BeginInvoke(new changeObjVisibleDelegate(changeObjVisible), new object[] { visibility, obj });
return;
}
// downcast to the correct obj
if (obj is Panel) {
Panel panel = (Panel)obj;
panel.Visible = visibility;
}
if (obj is Label) {
Label lbl = (Label)obj;
lbl.Visible = visibility;
}
}
private delegate void updateTextDelegate(string text, Label lbl);
private void updateText(string text, Label lbl) {
if (this.InvokeRequired) {
this.BeginInvoke(new updateTextDelegate(updateText), new object[] { text, lbl });
return;
}
lbl.Text = text;
}
第二次激活表单时,它确实可以正常工作,例如:
更新
我在阅读AlexF answer之后得到了一个解决问题的想法,但它看起来不是理想的解决方案:
我创建了一个while条件,它只会在两个线程都不活动时停止,并且在它内部有一个if条件,它将获得这个时间点并执行我需要的东西:
while (availableDatesThread.IsAlive || checkSiteThread.IsAlive) {
// At least one thread is still alive, keeps checking it...
if (!availableDatesThread.IsAlive && !checkSiteThread.IsAlive) {
// Both threads should be dead now and the panels not visible
WhoLunchTable.Visible = false;
WhoLunchTable.SuspendLayout();
listOfAvailableGroups.Clear();
WhoLunchTable.Controls.Clear();
WhoLunchTable.RowStyles.Clear();
PopulateTable();
WhoLunchTable.Visible = true;
WhoLunchTable.ResumeLayout();
break;
}
}
答案 0 :(得分:1)
第一次代码没有进入while循环时读代码因为selectSitePanel.Visible和selectAvailabilityPanel.Visible都为真:这是因为availableDatesThread.Start();和checkSiteThread.Start();已经开始但没有完成;这两个调用没有阻塞,所以代码继续并跳过这一步。 同时,两个背景线程完成,因此第二次“激活”事件被提升时,变量值是“正确的”(至少在最后一个周期)。
在没有等待线程完成的情况下,在获得所需值的结果之前,您正在查看代码。
换句话说,最好不要使用后台线程来更新界面以供您使用。
如果需要,可以继续按照使用方式使用代码,但在两个单独的函数中移动“while”部分:当线程完成工作并在此时刷新窗口时可以调用它们。不在“激活”事件中。