2012-06-08 130 views
1

我一直在試圖弄清楚這個問題。談到線程時我很困惑。動態更新UI時執行線程

我想要做的是在函數中有1個暫停的延遲,並繼續該功能,直到另一個1秒的暫停出現,並最終完成該功能。

public partial class SplashScreen : Form 
{ 
    public SplashScreen() 
    { 
     InitializeComponent(); // initalize splash screen 
     DatabaseStatus(); // set database connection 
     getUserInfo(); // get user information 
     showInfo(); // show app information on splash screen 
     System.Threading.Thread wa = new System.Threading.Thread(new System.Threading.ThreadStart(checkUser)); 
     wa.IsBackground = true; 
     wa.Start(); 
    } 

    void checkUser() 
    { 
     if (RegisteredUser) 
     { 
      richTextBox1.Text += "Loading user settings..."; // SHOW THIS TEXT AND WAIT 1 SECOND UNTIL NEXT 
      System.Threading.Thread.Sleep(1000); 

      if (DATABASE_CONNECTION) 
      { 
       richTextBox1.Text += "Loging on..."; 
       // WAIT AGAIN 1 SEC AND CONTINUE/// 
       LoginCheck login = new LoginCheck(USER_NAME, PASSWORD); 
       if (login.LOGIN_SUCESS) 
       { 
        richTextBox1.Text += "Sucess!"; 
        // SHOW THIS TEXT AND WAIT 1 SEC UNTIL SPLASH SCREEN FADE OUT// 
        //MessageBox.Show(login.HASH); 
        opac.Interval = 12; 
        opac.Start(); 
        opac.Tick += new EventHandler(dec); 
       } 
       else 
       { 
        MessageBox.Show(login.HASH); 
       } 
      } 
     } 
     else 
     { 
      richTextBox1.Text += "Not user profile found..."; 
      // ask user to register 
     } 
    } 
} 

我在哪裏放置了意見就是我想要的線程暫停和繼續...

任何人有任何輸入?

感謝

+0

http://www.google.com/search?q=update%20ui%20background%20thread –

回答

1

我會建議你做的一切都在一個獨立的後臺工作線程,並更新UI的狀態。這使得用戶界面更快速,應用程序可靠。

http://msdn.microsoft.com/en-us/library/cc221403(v=vs.95).aspx

+0

期間火張望了一下後打碼並看着你給了mem的鏈接我終於得到它的工作! – Dimitri

+0

不錯。 THanks :) –

0

你需要使用的invoke()見this

2

首先,你必須使用的WinForms工作時知道(和WPF/Silverlight的,對吧?),你不能,不應該從操縱任何其他線程的UI元素,除了創建的原形式/控制。

如果您需要執行異步工作,您需要使用InvokeBeginInvoke將UI工作轉換回表單或控件的線程。另外,考慮使用代表(MethodInvoker很方便),而不是創建自己的線程。

此外,您需要在Load事件期間或之後開始異步工作,否則您的邏輯將在表單顯示之前開始執行(請參閱下面的示例)。

我把你的例子,並把它放入我自己的簡化樣本。

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 

     RegisteredUser = true; 
     DATABASE_CONNECTION = true; 


    } 

    private void UpdateStatus(string message) 
    { 
     BeginInvoke(new MethodInvoker(() => richTextBox1.Text += message)); 
    } 

    private void CheckUser() 
    { 
     if (RegisteredUser) 
     { 
      UpdateStatus("Loading user settings..."); // SHOW THIS TEXT AND WAIT 1 SECOND UNTIL NEXT 
      System.Threading.Thread.Sleep(1000); 

      if (DATABASE_CONNECTION) 
      { 
       UpdateStatus("Logging on..."); 
       //// WAIT AGAIN 1 SEC AND CONTINUE/// 
       //LoginCheck login = new LoginCheck(USER_NAME, PASSWORD); 
       if (true)//login.LOGIN_SUCESS) 
       { 
        UpdateStatus("Success!"); 
        // SHOW THIS TEXT AND WAIT 1 SEC UNTIL SPLASH SCREEN FADE OUT// 
        //MessageBox.Show(login.HASH); 
        //opac.Interval = 12; 
        //opac.Start(); 
        //opac.Tick += new EventHandler(dec); 
       } 
       else 
       { 
        //MessageBox.Show(login.HASH); 
       } 
      } 
     } 
     else 
     { 
      UpdateStatus("No user profile found."); 
      // ask user to register 
     } 
    } 

    protected bool DATABASE_CONNECTION { get; set; } 

    protected bool RegisteredUser { get; set; } 

    private void Form1_Load(object sender, EventArgs e) 
    { 
     var invoker = new MethodInvoker(CheckUser); 
     invoker.BeginInvoke(null, null); 
    } 
} 

正如你所看到的,我用的方法,如UpdateStatus做的UI爲我工作,確保其在UI線程上完成的。您可以使用任意數量的類似方法在UI中執行其他操作,例如觸發表單或任何其他內容的淡入淡出。

你甚至不應該在UI線程之外顯示消息框;通過類似的方法安全地調用它們(同樣,爲了調試,只需要Debug.WriteLine將消息寫入調試器而不是全部彈出消息框)。

+0

感謝您的意見。不過,在表單顯示之前,我仍然遇到了邏輯完成的問題。通常情況下,表單需要將近1秒才能完全加載。使用這種方法,表單需要5秒來完成上次UpdateStatus消息的加載。我想要做的是創建一個啓動畫面並在文本框中顯示狀態更新。 – Dimitri

+0

我將不得不看到你的更新代碼。也許你錯過了我指定的改變之一。我創建的例子正是我所解釋的。 – HackedByChinese

0
public partial class SplashScreen : Form 
{  
    bool DATABASE_CONNECTION; 
    bool RegisteredUser; // if user has been registered 
    string USER_NAME; 
    string PASSWORD; 
    double LIN_x = 0.01; 

    DialogResult result; 
    custom con = new custom(); 
    Timer opac = new Timer(); 

    public SplashScreen() 
    { 
     InitializeComponent(); // initalize splash screen 
     DatabaseStatus(); // set database connection 
     getUserInfo(); // get user information 
     showInfo(); // show app information on splash screen 
    } 

    private void UpdateStatus(string message) 
    { 
     BeginInvoke(new MethodInvoker(() => richTextBox1.Text += message + Environment.NewLine)); 
    } 

    void checkUser() 
    { 
     UpdateStatus("Loading user settings..."); 
     if (RegisteredUser) 
     { 
      UpdateStatus("User " + USER_NAME + " found."); 
      if (DATABASE_CONNECTION) 
      { 
       UpdateStatus("Logging on..."); 
       LoginCheck login = new LoginCheck(USER_NAME, PASSWORD); 
       if (login.LOGIN_SUCESS) 
       { 
        UpdateStatus("Success! Loading " + con.AppTitle() + "...please wait"); 

        //UpdateStatus(login.HASH); return hash string from web site 
        fadeSplash(); // begin fade out of form 
       } 
       else 
       { 
        UpdateStatus("There was an error logging in."); 

       } 
      } 
      else 
      { 
       UpdateStatus("No database connection found."); 

      } 
     } 
     else 
     { 
      UpdateStatus("No user found"); 

      Reg(); // Registration form 
     } 
    } 

    private void fadeSplash() 
    { 
     opac.Interval = 12; 
     opac.Tick += new EventHandler(dec); 
     opac.Start(); 
    } 

    private void dec(object sender, EventArgs e) 
    { 
     this.Opacity -= LIN_x; 
     if (this.Opacity < 0.04) 
     { 
      opac.Stop(); 
      this.Hide(); 
      main open = new main(); // start application 
      open.Show(); 
     } 
    } 
} 

這裏就是淡入淡出方法不MethodInvoke

+0

您仍然有從非UI線程顯示的消息框和表單。 'BackgroundWorker'似乎不適合執行此任務,因爲儘管至少有一種情況需要在異步線程中暫停執行並提示用戶輸入,並將該輸入返回到異步線程並繼續工作。 'BackgroundWorker'不支持這個;你開始工作,發佈進度更新,然後在結束時完成或取消工作。你需要更具互動性的東西,這就是爲什麼我給你答案的原因。 – HackedByChinese

+0

這是我的不好。這花了這麼長時間的原因是因爲我在另一臺PC上工作,該PC的Windows主機沒有正確解析我的私有服務器並導致DATABASE_CONNECTION布爾失敗......我不得不超時。 無論如何,我重新嘗試了你的方法,只做了一些小小的調整,而且效果很好。我的問題是,什麼時候應該使用Invoke,什麼時候應該使用BackgroundWorker? 另外,我怎樣才能停止線程?例如,如果用戶未找到並開始提示,我希望它停止。 再次感謝 – Dimitri

+0

如果可以的話,我會選擇'BackgroundWorker',因爲它已經爲您完成了並且易於使用。但是,如果您只需要以下內容,「BackgroundWorker」僅對您有用:1.開始工作異步2.關閉進度通知3.工作完成時發出信號。正如我在之前的評論中所說的,你的工作更具互動性,所以'BackgroundWorker'不太適合賬單(但幾乎可以)。 – HackedByChinese