2012-12-25 34 views
2

我一直在用RichTextBox.ScrollToCaret遇到一個有點令人沮喪的障礙。我有將消息輸出到RichTextBox的代碼。當每條消息發送到表單時,它將被拆分成多行並進行格式化,然後將每行連接起來並將結果發送到RichTextBox.Append。然後,滾動到下面的兩個電話框的底部:由XNA遊戲發佈的表單中的RichTextBox.ScrollToCaret出現AccessViolationException

outputBox.Select(outputBox.Text.Length, 0); 
outputBox.ScrollToCaret(); 

當打印一條消息時,它很好。當打印一小撮消息時,沒有問題。當連續快速打印一串消息時,它會隨機發送一個消息(在它發生之前打印多少條消息),並拋出一個AccessViolationException異常(「試圖讀取或寫入受保護的內存,這通常表示其他內存已損壞。」,全部詳細信息here下一次在該框上添加名爲的添加下一條消息。這個只有發生在快速連續執行時,並且只有每次使用RichTextBox.ScrollToCaret時。下面的代碼,我就回落正常工作:

outputBox.Focus(); 
outputBox.Select(outputBox.Text.Length, 0); 

我發現過,即使我捕捉到的異常,並把它扔了,程序會掛在附加的下一次調用。所以,我認爲這是RichTextBox中實際代碼的問題。有人有主意嗎?

如果有人需要它,我可以發佈更多我的代碼,但情況確實非常基礎。需要注意的是,沒有多線程(除了固有的UI線程),所以發送消息的對象和接收它們的表單在同一個線程中。此外,這是在.NET 4.0下。

我發現這個問題解決了這個問題,但只提供了一個解決方法,沒有真正的解釋:AccessViolation occurs in RichTextBox.ScrollToCaret。不幸的是,我的線程經驗並不是我想要的地方,所以我無法讓他們的解決方案正常工作,但幸運的是,我上面發佈的工作很好。

更新1

因此,它看起來經過一些像它的測試有事情做與XNA,所以它可能是我如何與線程工作的誤解。我一直無法在純WinForms應用程序中重現錯誤,但可以通過簡單的XNA遊戲輕鬆完成。我已經在這裏拉鍊讓你看。抱歉的錯誤。 https://dl.dropbox.com/u/16985121/StackOverFlowExamples.zip

+0

是調用不同的線程比.Append調用。選擇()調用? – cppanda

+0

不,我寫的所有內容都發生在主線程上。所以就是這個和UI線程。 –

+0

public delegate void WriteLogEntryDelegate(string log_entry); 空隙WriteLogEntryCB(串log_entry) { 如果(richTextBox1.InvokeRequired == TRUE){ 變種 = d新WriteLogEntryDelegate(WriteLogEntryCB);這個.Invoke(d,log_entry); } else { richTextBox1.AppendText(log_entry +「\ r \ n」); this.richTextBox1.SelectionStart = this.richTextBox1.Text.Length; this.richTextBox1.ScrollToCaret(); } } –

回答

0
public delegate void WriteLogEntryDelegate(string log_entry); 

    void WriteLogEntryCB(string log_entry) 
    { 
     if (richTextBox1.InvokeRequired == true) 
     { 
      var d = new WriteLogEntryDelegate(WriteLogEntryCB); 
      this.Invoke(d, log_entry); 
     } 
     else 
     { 
      richTextBox1.AppendText(log_entry + "\r\n"); 
      this.richTextBox1.SelectionStart = this.richTextBox1.Text.Length; 
      this.richTextBox1.ScrollToCaret(); 
     } 
    } 
+0

正如我在上面的評論中所說的,不幸的是,這段代碼並沒有解決這個問題。這似乎使例外不那麼頻繁,雖然我不能肯定地說。但是,它確實改變了它,所以有時候不是拋出一個AccessViolatedException,而是無限期地掛在AppendText上,VS2010告訴我在調用堆棧上有一個本地框架。 –

1

我有同樣的問題。我有一點不同的情況,但基本上相同的問題。我用C++/CLI和C#表單混合了代碼。

來自C++/CLI的線程之一調用C#表單中的函數將消息打印到richtextbox上。

'緩慢'調用此函數是可以的。但是如果調用函數發生得非常快並且經常發生,程序會隨機崩潰。

這是我的代碼。

void PrintOutLog(System::String^ s) 
    { 
     Monitor::Enter(this->richTextBox_LogBox); 
     try 
     { 
      if(this->richTextBox_LogBox->InvokeRequired) 
      { 

       AddListItem^ d = gcnew AddListItem(this, &PrintOutLog); 
       array<Object^>^ myStringArray = {s}; 
       this->richTextBox_LogBox->BeginInvoke(d, myStringArray); 
      } 
      else 
      {     
       this->richTextBox_LogBox->AppendText(s + "\n"); 
       this->richTextBox_LogBox->SelectionStart = this->richTextBox_LogBox->Text->Length; 
       this->richTextBox_LogBox->ScrollToCaret(); 
      } 

     } 
     finally 
     { 
      Monitor::Exit(this->richTextBox_LogBox); 
     } 

    } 

事實證明,如果我註釋掉兩行代碼,程序不會因內存訪問衝突而再次崩潰。

this->richTextBox_LogBox->SelectionStart = this->richTextBox_LogBox->Text->Length; 
this->richTextBox_LogBox->ScrollToCaret(); 

如果我評論這兩條線出來,然後在RichTextBox不會顯示在文本框的末尾新的日誌消息時,C#的形式沒有焦點。

我可以使用你的解決方案,它在放置文本之前變得越來越集中,但如果我這樣做,它總是停留在我需要保持最頂級的其他窗口之上。所以我不能那樣做。

我擡頭看MSDN頁http://msdn.microsoft.com/en-us/library/system.windows.forms.textboxbase.scrolltocaret.aspx,發現在頁面中間說這個。

如果控件沒有焦點或插入符號已經位於控件的可見區域,則此方法無效。

但我相信這是不正確的。看起來好像當焦點不在richtextbox控件上時調用ScrollToCaret()時,我可以看到richtextbox的滾動條在獲取新消息時向下移動,這意味着它會打印消息並更新,即使它沒有焦點。

我試圖鎖定richtextbox從多線程安全,但它沒有解決訪問衝突問題。如果除了使用focus()函數之外還有其他解決方案來解決這個問題,那將會非常棒。

謝謝。

+0

我很高興我不是唯一一個這樣做的人,讓我發瘋。自從我發佈這篇文章後,我發現這個解決方案可以繞過對我來說完全正常的問題,並希望對您也有好處。 http://stackoverflow.com/a/8562457/568042 –

+0

太棒了!非常感謝你。我會嘗試使用它,我相信它也會對我有用,因爲我們有相同的問題。 :) – diehard98

+0

我修改了基於你的鏈接的代碼,它確實有效。我可能需要測試幾個其他設置,但我想它工作正常。對我來說,另一件事是設置WM_VSCROLL和SB_PAGEBOTTOM的方式稍有不同,因爲我的應用程序已經在代碼的C++端定義了它。所以,似乎我需要用一些不同的名稱來定義它們,但它具有相同的值。再次感謝你。 – diehard98