2011-12-27 119 views
-1

我正在處理以下處理線程和線程優先級的程序。C#空引用異常

我已經構建了一個窗體窗體,其中包含一個富文本框(DisplayTextBox)和兩個按鈕(用於運行應用程序的StartButton和用於關閉應用程序的ExitButton)。

在窗體中,我創建了幾個線程並且一個接一個地運行它們。每個線程使用的方法都可以在Threading類中找到。有問題的方法是PrintOnScreen()。

在此方法中,我將線程名稱以及其優先級附加到StringBuilder類型的字符串。然後我想在DisplayTextBox(它在Form.cs中)中顯示str的內容。

但是,我得到一個「NullReferenceException未處理:對象引用未設置爲對象的實例」錯誤。錯誤總結如下:

DisplayTextBox.Text = Convert.ToString(str);

你能幫我解決這個錯誤嗎?謝謝。

編輯

感謝所有您的幫助。爲了解決這個問題,我將PrintOnScreen方法複製到Form.cs類並放棄了Threading.cs。

我後來使用了Anand給出的代碼並將它放在t2.Join()之下。現在它像一個魅力。

+0

你知道哪個對象爲null嗎?這個問題只有兩個可能的答案,第一個會是** DisplayTextBox **第二個會是** str **當然,我沒有看到您在表單上傳遞對DisplayTextBox的引用。線程繼承Form1並不意味着它具有對Form1上控件的引用。 – 2011-12-27 12:21:24

+0

即使您確實修復了代碼並將引用傳遞給了** DisplayTextBox **,也必須調用更改文本,因爲您無法修改除主UI線程之外的單獨線程中的控件。 – 2011-12-27 12:23:50

+0

您應該真的考慮同步對從多個線程訪問的數據的訪問。例如,你是用兩個線程寫入同一個StringBuilder實例並迭代Threads-collection。 – Jan 2011-12-27 12:26:51

回答

3

問題發生在窗體的構造函數中。您再次聲明DisplayText作爲本地成員,以便表單的字段未初始化。像這樣改變你的構造函數:

private void Form1_Load(object sender, EventArgs e) 
{ 
    DescTextBox.Visible = false; 
    DisplayTextBox = new RichTextBox(); 
    DisplayTextBox.Location = new Point(15, 31); 
    DisplayTextBox.Height = 258; 
    DisplayTextBox.Width = 303; 
    panel1.Controls.Add(DisplayTextBox); 
} 

它應該像你期望的那樣工作。

編輯︰但要小心你會得到的問題,當你想從後臺工作線程更改UI元素。在這些情況下,您將不得不使用調用模式。

1

您不能與除主應用程序線程以外的任何其他線程的控件進行通信。你需要爲此使用dispather。看看這裏:http://msdn.microsoft.com/en-us/library/system.windows.threading.dispatcher.aspx

編輯
@Fischermaen - 嘿,沒有注意到這一點,但它仍然不會因爲線,在那裏他寫失敗的工作。他仍然需要使用調度設置從非主線程控制

EDIT 2個
相關主題的Text屬性:
How to update the GUI from another thread in C#?
In WinForms, why can't you update UI controls from other threads?

+0

感謝關於調度員的建議。我會嘗試一下,讓它知道它是否有效。感謝大家:) – Joe 2011-12-27 12:33:36

1

我簡單的控制檯應用程序嘗試這個它運行良好。 問題出在DisplayTextBox上。如果你想與任何控件進行交互,那麼你必須使用UI線程或Dispatcher。 使用在你的線程類下面的代碼中,而是

DisplayTextBox.Text = Convert.ToString(str); 

使用這一個

Dispatcher.Invoke(DispatcherPriority.Normal, 
        new Action(
      delegate() 
      { 
       DisplayTextBox.Text = Convert.ToString(str); 
      } 
     )); 
+0

沒錯。在控制檯應用程序中,它工作正常。它給我的問題是,當我嘗試將其轉換爲Windows應用程序。 – Joe 2011-12-27 12:32:34

+0

嘗試上面的代碼。它應該工作正常。 – Anand 2011-12-27 12:33:50

+0

我粘貼了代碼,它給了我錯誤 - 名稱'Dispatcher'在當前上下文中不存在。 – Joe 2011-12-27 12:40:07

0

庵。 從這裏看不到,但是你遇到困難的部分原因是代碼中缺少封裝和糟糕的生命週期管理。

在PrintOnScreen方法中實例化str,給它一個更好的名字,沒有appranrent需要成爲成員變量,根本不需要公開。

代替具有空隙的結果,它已經返回字符串結果

例如

SomeTextBox = PrintOnScreen(); // (GetThreadDetails might be a better name...) 

作爲提示不要混合表示和邏輯。讓你的用戶界面控制徹底在任何擁有它們。

,不要做

public SomeType SomeName; 

使其屬性,並給它getter和一個setter,即使是短期形式

公共SOMETYPE SomeName {獲得;設置;}

其他代碼位可以做一些真正愚蠢像

Form1.SomeType = (SomeOtherType)someVar; // with appaling consequences. 

沒有什麼應該有一個以上的所有人,任何其他路徑引向絕路。 PS:str.ToString()是比Convert.ToString(str)更好的選擇;

0

嗯,這對我來說不是很清楚你想要達到什麼目的,然而問題是當你試圖訪問控制時,基本形式Threading類繼承自未被加載(窗口句柄仍然不存在)這也是你在Form1本身上什麼也看不到的原因,因爲你的線程輸出爲隱藏的形式,這是不顯示的。

我認爲你正在嘗試解決由SOReader引發的線程訪問問題。這不是這樣做的正確方法。