C# BeginInvoke方法何时运行?
我有两个线程使用BeginInvoke方法将某些Windows窗体对象(面板和标签)的可见性属性更改为false。问题是我不确定更改何时发生。我可以看到面板不在那里(因此BeginInvoke方法起作用),但是我检查可见性状态的if条件在第一次激活表单时总是返回trueC# BeginInvoke方法何时运行?,c#,multithreading,winforms,C#,Multithreading,Winforms,我有两个线程使用BeginInvoke方法将某些Windows窗体对象(面板和标签)的可见性属性更改为false。问题是我不确定更改何时发生。我可以看到面板不在那里(因此BeginInvoke方法起作用),但是我检查可见性状态的if条件在第一次激活表单时总是返回true bool notVisible = false; private void LunchMainScreen_Activated(object sender, EventArgs e) { String CurrentS
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;
}
当代码第一次没有进入while循环时读取代码,因为selectSitePanel.Visible和selectAvailabilityPanel.Visible为true:这是因为AvailabledTestThread.Start()为true;和checkSiteThread.Start();已开始但尚未完成;这两个调用没有阻塞,因此代码继续并跳过。 同时,两个backgrund线程完成,因此第二次引发“Activated”事件时,变量值是“correct”(至少在上一个周期中是正确的) 不必等待线程完成,您就可以在获得所需值的结果之前快速浏览代码 换句话说,最好不要使用后台线程来更新您需要的接口
如果需要,您可以继续使用代码,但在两个单独的函数中移动“while”部分:当线程完成其工作并在此时刷新窗口时,可以调用它们,而不是在“activate”中事件。据我所知,您正在使用后台线程设置WinForms控件的属性。WinForms文档声明,您只能在创建WinForms控件的同一线程上与它们交互。为什么你需要使用一个后台线程呢?或者它们是在不同的线程上创建的,而不是调用
午餐主屏幕激活()。我选择使用线程与WinForms控件交互,这样它们可以同时运行(考虑到一个与另一个无关),从而减少表单完成加载所需的时间。任何关于如何通过不同流程实现相同目标的建议都是非常受欢迎的:)您确定存在性能问题吗?如果窗体即使在主线程上设置可见性时也可以正常加载,那么就没有理由使用线程。此外,我读到的所有内容都表明,对WinForms控件的所有访问必须位于创建它们的同一线程上。这次你也许可以侥幸逃脱,但我也可以看到这一点随机失败。你的回答没有解决问题,但给了我解决问题的思路。这看起来不是最好的解决方案,所以我将用新代码更新我的问题,看看是否还有进一步的改进需要做。谢谢
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;
}
}