2012-04-19 104 views
2

希望這不是太難以遵循。代碼生成器生成的表單不能正確顯示

我目前正在研究一個在後檯安靜地運行的小時間記錄應用程序。每當股票行情下跌時,應用程序都會提示用戶說出自上次提示後他/她做了什麼。我最終會讓應用程序將數據寫入電子表格。

一個我有選擇至今使用戶能夠選擇是否他/她想使用默認的提示設置(每一個提示失手的時候,它保持可見,直到創建了下一個,意義如果用戶離開他/她的計算機一段時間,可能會有幾個提示等待被填充),或者想要合併所有提示(每次錯過提示並彈出新提示時,舊的關閉,新的覆蓋舊的提示和新的提示時間)。

用戶還可以選擇一個複選框來關閉提示。當他/她再次提示提示時,會彈出一個提示,要求用戶在提示關閉時填寫他/她正在做的事情(當用戶正在運行全屏應用程序等時有用)。

我的問題是,當我嘗試生成提示時,它們無法正確顯示。我無法操縱它們,也沒有任何控件顯示。他們基本上看起來像空的形式。

這是我使用的股票代碼生成提示代碼:

public void ticker(object source, System.Timers.ElapsedEventArgs e) 
    { 
     if (groupMissed) 
     { 
      incrementsMissed += 1; 
      if (incrementsMissed > 1) 
      { 
       IncrementForm form = (IncrementForm)Application.OpenForms["IncrementForm"]; 
       if (form.InvokeRequired) 
       { 
        form.Invoke(new MethodInvoker(delegate { form.Close(); })); 
       } 
      } 
     } 
     else 
     { 
      incrementsMissed = 1; 
     } 

     IncrementForm theIncrementForm = new IncrementForm(this, e.SignalTime); 
     theIncrementForm.Show(); 
     latestIncrement = e.SignalTime; 
    } 

這是我的生成使用提示代碼「提示音關」複選框:

private void chkbxAlerts_Click(object sender, EventArgs e) 
    { 
     if (!chkbxAlerts.Checked) 
     { 
      // Ensures that the time missed is covered and restarts the timer 
      DateTime now; 
      now = DateTime.Now; 
      if ((now - latestIncrement).TotalMinutes >= 1) // Only records time if it is equal to or greater than one minute 
      { 
       // TO-DO: FIX 
       if (groupMissed) 
       { 
        incrementsMissed += 1; 
        if (incrementsMissed > 1) 
        { 
         IncrementForm form = (IncrementForm)Application.OpenForms["IncrementForm"]; 
         if (form.InvokeRequired) 
         { 
          form.Invoke(new MethodInvoker(delegate { form.Close(); })); 
         } 
        } 
       } 
       else 
       { 
        incrementsMissed = 1; 
       } 
       IncrementForm theIncrementForm = new IncrementForm(this, now, latestIncrement); 
       theIncrementForm.Show(); 
       latestIncrement = now; 
      } 
      timer.Enabled = true; 
     } 
     else 
     { 
      // Stops the timer 
      timer.Enabled = false; 
     } 
    } 

如果你需要進一步澄清, 請告訴我。非常感謝您提供任何幫助,這一直困擾着我。

+0

一個很好的問題 - 雖然還有一些缺失的東西。你的股票是一個計時器驅動?計時器正在從另一個線程調用 - 你不能從那裏更新GUI表單(儘管你可以在不同線程中顯示/產生表單 - 不確定在你的情況下最終會給出什麼)......是的,這是另一個線程確定 – NSGaga 2012-04-19 00:55:40

+0

是的,股票在定時器上由Elapsed事件調用。我如何解決你提到的這個GUI問題? – Djentleman 2012-04-19 00:57:36

+0

你能製作一個小的'可運行'的例子嗎?還有更多這個我猜 – NSGaga 2012-04-19 01:06:02

回答

2

System.Timers.TimerSynchronizingObject屬性。如果將其設置爲主窗體(或包含該定時器的窗體),則在GUI線程上會引發計時器滴答事件。

請注意,System.Timers.Timer有令人討厭的習慣,吞嚥Elapsed事件中發生的異常。如果你的滴答處理程序拋出異常,你永遠不會看到它。這是一個討厭的bug。爲此,我建議使用System.Windows.Forms.TimerSystem.Threading.Timer。如果使用Windows窗體計時器,則在GUI線程上引發已用事件。如果你使用System.Threading.Timer,你必須使用Invoke作爲NSGaga在他的回答中顯示。

請參閱Swallowing exceptions is hiding bugs瞭解更多關於爲什麼我勸阻使用System.Timers.Timer的信息。

+0

您的解決方案運行良好,謝謝!就一件事。 System.Windows.Forms.Timer似乎沒有與System.Timers.ElapsedEventArgs.SignalTime等效,所以我只是使用DateTime.Now來代替。以爲你可能想知道你是否還沒有。 – Djentleman 2012-04-19 02:26:36

+0

@Djentleman與這一個去 - 我更喜歡這個答案:) – NSGaga 2012-04-19 11:50:37

2

我認爲,從我可以看到的不是100%,但你的計時器是在一個單獨的線程(從計時器ticker調用)產卵你的窗口。

雖然理論上可以工作(看看這個How to open a form in a thread and force it to stay open
...你可能會更好的停留在主線程內。

嘗試這樣的事情......

yourMainWindow.Invoke(new MethodInvoker(() => 
    { 
     IncrementForm theIncrementForm = new IncrementForm(this, e.SignalTime); 
     theIncrementForm.Show(); 
     latestIncrement = e.SignalTime; 
    })); 

...這是從你的計時器 - 這樣(我可以看到),你應該擁有一切「的主線程」,使事情變得更加簡單爲你。

希望這有助於

+0

非常感謝您的幫助!即使我沒有最終使用你的方法,你確實幫助我理解了更多的線程。再次感謝! – Djentleman 2012-04-19 02:27:41