我在使用 RichTextBox.ScrollToCaret 时遇到了一些令人沮丧的障碍。我有将消息打印到 RichTextBox 的代码。当每条消息发送到表单时,它被分成多行并格式化,然后连接每行并将结果发送到 RichTextBox.Append。然后,进行以下两个调用以滚动到框的底部:
outputBox.Select(outputBox.Text.Length, 0);
outputBox.ScrollToCaret();
打印一条消息时,没问题。打印少量消息时,没有问题。当快速连续打印一堆消息时,它会随机(在发生之前打印多少条消息)抛出 AccessViolationException(“尝试读取或写入 protected 内存。这通常表明其他内存已损坏。”,full详细信息 here ) 下次在该框中调用追加时添加下一条消息。这种情况仅在快速连续执行时发生,并且仅在每次使用 RichTextBox.ScrollToCaret 时发生。我使用的以下代码运行良好:
outputBox.Focus();
outputBox.Select(outputBox.Text.Length, 0);
我还发现,即使我捕获了异常并将其丢弃,程序也会在下次调用 Append 时挂起。所以,我认为这是 RichTextBox 中实际代码的问题。大家有什么想法吗?
如果有人需要,我可以发布更多我的代码,但情况确实非常基本。需要注意的一些事情是,没有多线程(除了固有的 UI 线程之外),因此发送消息的对象和接收消息的表单位于同一线程上。另外,这是在 .NET 4.0 下。
我发现另一个问题解决了这个问题,但只提供了解决方法,没有真正的解释:AccessViolation occurs in RichTextBox.ScrollToCaret 。不幸的是,我在线程方面的经验不是我想要的,所以我无法让他们的解决方案正常工作,但幸运的是我上面发布的内容工作得很好。
更新 1
所以它会进行一些测试,就像它与 XNA 有关,所以这可能是我对其如何与线程一起工作的误解。我无法在纯 WinForms 应用程序中重现该错误,但可以通过简单的 XNA 游戏轻松完成。我把这两本都压缩到这里给你看。对于错误表示歉意。 https://dl.dropbox.com/u/16985121/StackOverFlowExamples.zip
最佳答案
我也遇到了同样的问题。我的情况略有不同,但问题基本相同。我将代码与 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();
如果我注释掉这两行,那么当 C# 表单没有焦点时,richtextbox 不会在文本框末尾显示新的日志消息。
我可以使用您的解决方案,该解决方案在放置文本之前获得焦点,但如果我这样做,它总是位于我需要保持在最上面的其他窗口的顶部。所以我不能这么做。
我查阅了MSDN页面http://msdn.microsoft.com/en-us/library/system.windows.forms.textboxbase.scrolltocaret.aspx并在页面中间发现这样的内容。
如果控件没有焦点或者插入符号已位于控件的可见区域中,则此方法无效。
但我相信这不是真的。似乎当焦点不在 RichTextBox 控件上时调用 ScrollToCaret() 时,我可以看到 RichTextBox 的滚动条在收到新消息时向下移动,这意味着它打印消息并更新,即使它没有焦点。
我尝试锁定富文本框以免受多线程的影响,但它没有解决访问冲突问题。如果除了使用 focus() 函数之外还有其他解决方案来解决此问题,那就太好了。
谢谢。
关于c# - XNA 游戏启动的表单中带有 RichTextBox.ScrollToCaret 的 AccessViolationException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14027505/