C# XNA games发布的表单中的RichTextBox.ScrollToCaret访问违反例外

C# XNA games发布的表单中的RichTextBox.ScrollToCaret访问违反例外,c#,.net,winforms,richtextbox,access-violation,C#,.net,Winforms,Richtextbox,Access Violation,我在使用RichTextBox.ScrollToCaret时遇到了一些令人沮丧的障碍。我有将消息打印到RichTextBox的代码。将每条消息发送到表单时,会将其拆分为多行并格式化,然后将每行连接起来,并将结果发送到RichTextBox.Append。然后,进行以下两个调用以滚动到框的底部: outputBox.Select(outputBox.Text.Length, 0); outputBox.ScrollToCaret(); 当打印一条消息时,它就可以了。打印少量消息时,没有问题。在快

我在使用RichTextBox.ScrollToCaret时遇到了一些令人沮丧的障碍。我有将消息打印到RichTextBox的代码。将每条消息发送到表单时,会将其拆分为多行并格式化,然后将每行连接起来,并将结果发送到RichTextBox.Append。然后,进行以下两个调用以滚动到框的底部:

outputBox.Select(outputBox.Text.Length, 0);
outputBox.ScrollToCaret();
当打印一条消息时,它就可以了。打印少量消息时,没有问题。在快速连续打印一组消息时,它将随机(在打印之前打印多少消息)抛出AccessViolationException(“尝试读取或写入受保护的内存。这通常表示其他内存已损坏。”,完整详细信息)下次在该框上调用Append以添加下一条消息。此仅在快速连续操作时发生,而仅在每次使用RichTextBox.ScrollToCaret时发生。我所依赖的以下代码运行良好:

outputBox.Focus();
outputBox.Select(outputBox.Text.Length, 0);
我还发现,即使捕获到异常并将其丢弃,程序仍将在下一次调用Append时挂起。所以,我假设RichTextBox中的实际代码有问题。有人有什么想法吗

如果有人需要,我可以发布更多的代码,但情况确实相当基本。需要注意的是,没有多线程(除了固有的UI线程),因此发送消息的对象和接收消息的表单位于同一线程上。此外,这是在.NET4.0下实现的

我发现另一个问题解决了这个问题,但只提供了一个解决方法,没有真正的解释:。不幸的是,我在线程方面的经验不是我想要的,所以我无法让他们的解决方案正常工作,但幸运的是,我上面发布的内容工作得很好

更新1 因此,在进行了一些测试之后,它看起来似乎与XNA有关,因此,这可能是我对线程如何工作的误解。我无法在纯WinForms应用程序中重现错误,但可以通过一个简单的XNA游戏轻松完成。我把两个拉链都拉在这里给你看。为这个错误道歉。
我也有同样的问题。我有一些不同的情况,但基本上是相同的问题。我把代码与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);
        }

    }
如果我将这两行注释掉,那么当C#表单没有焦点时,richtextbox不会在文本框的末尾显示新的日志消息

我可以使用你的解决方案,在放文本之前先获得焦点,但如果我这样做,它总是保持在其他窗口的顶部,我需要保持在顶部。所以我不能那样做

我查阅了MSDN页面,发现在页面的中间写着这个。

如果控件没有焦点或插入符号已定位在控件的可见区域,则此方法无效。

但我相信这不是真的。似乎当焦点不在richtextbox控件上时调用ScrollToCaret()时,我可以看到richtextbox的滚动条在收到新消息时向下移动,这意味着它打印消息并更新,即使它没有焦点

我试图锁定richtextbox以避免多线程,但这并没有解决访问冲突问题。如果除了使用focus()函数之外,还有其他解决方案来解决此问题,那就太好了


谢谢。

在这里发现了另一个问题,它为我提供了一种完全绕过该问题的方法,以产生相同的输出,而不会出现任何问题:

是在不同的线程上调用的.Select()调用还是在.Append调用上调用的?不,我写的所有东西都发生在主线程上。这就是UI thread.public delegate void writelGentryDelegate(string log_条目);void WriteLogEntryCB(字符串日志项){if(richTextBox1.invokererequired==true){var d=new WriteLogEntryDelegate(WriteLogEntryCB);this.Invoke(d,日志项);}else{richTextBox1.AppendText(日志项+“\r\n”);this.richTextBox1.SelectionStart=this.richTextBox1.Text.Length;this.richTextBox1.ScrollToCaret();}}}尝试只调用它,尝试调用绑定到该方法的委托实例,并尝试调用表单上的委托实例,但均无效。我现在正试图制作一个例子,上传给大家,让大家仔细挑选。我已经更新了主要帖子,以反映我的测试。希望XNA不是你们的交易破坏者,但如果是,无论如何,谢谢!正如我在上面的评论中所说,不幸的是,这段代码并没有解决这个问题。这似乎减少了异常发生的频率,尽管我不能肯定这一点。然而,它确实改变了它,所以有时候它不会抛出AccessViolatedException,而是无限期地挂起AppendText调用,VS2010告诉我调用堆栈顶部有一个本机框架。我很高兴我不是唯一一个这样做的人,这让我发疯了。自从我发布了这篇文章,我发现这个解决方案可以绕过这个问题,它对我来说非常好,希望对你也一样。伟大的非常感谢你。我会尝试使用它,我相信它也会对我有用,因为我们有相同的问题。:)我根据你的链接修改了代码,它真的很有效。我可能需要测试与其他设置很少,但我想它的作品很好。对于我来说,一个不同的是,WMYVROND和SBBPGEAWATH设置的不同,因为我的应用程序已经在C++代码侧定义了它。所以,看起来李
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();