BeginInvoke方法何时运行?

时间:2014-03-06 16:55:43

标签: c# multithreading winforms

我有两个线程使用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;
}

第二次激活表单时,它确实可以正常工作,例如:

  1. 表单第一次加载,但不会进入while循环。
  2. 我最小化表单/程序。
  3. LunchMainScreen_Activated 再次运行,它可以正常工作,因为它识别出面板不可见。
  4. 更新

    我在阅读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;
        }
    }
    

1 个答案:

答案 0 :(得分:1)

第一次代码没有进入while循环时读代码因为selectSitePanel.Visible和selectAvailabilityPanel.Visible都为真:这是因为availableDatesThread.Start();和checkSiteThread.Start();已经开始但没有完成;这两个调用没有阻塞,所以代码继续并跳过这一步。 同时,两个背景线程完成,因此第二次“激活”事件被提升时,变量值是“正确的”(至少在最后一个周期)。

在没有等待线程完成的情况下,在获得所需值的结果之前,您正在查看代码。

换句话说,最好不要使用后台线程来更新界面以供您使用。

如果需要,可以继续按照使用方式使用代码,但在两个单独的函数中移动“while”部分:当线程完成工作并在此时刷新窗口时可以调用它们。不在“激活”事件中。