System.AccessViolationException发生在TextView.Buffer上

时间:2019-06-09 12:42:29

标签: c# mono monodevelop gtk#

我正在尝试使用Gtk#GUI在C#上每秒显示一行文本。 文本在.txt文件上,每行有4个整数。

但是当我在DragonFly BSD上编译它时,前一两行完美显示在文本框中,但是程序停止了,并且出现了SIGABRT和SIGSEGV错误。

所以我已经在Windows上编译了相同的代码,并且出现了以下错误:'System.AccessViolationException'之类的异常。

我检查了“允许使用不安全的代码”,但结果相同。

async void DisplayText(string FileName)
{
    string[] Temp = File.ReadAllLines(FileName);
    string[] ScoreBoard = new string[4];

    TextIter Ti = textview.Buffer.StartIter;

    foreach (string Line in Temp)
    {
        ScoreBoard = Line.Split('\t');

        await Task.Delay(1000);

        textview.Buffer.Insert(ref Ti, ScoreBoard[0]);
        textview.Buffer.Insert(ref Ti, "  |  ");
        textview.Buffer.Insert(ref Ti, ScoreBoard[1]);
        textview.Buffer.Insert(ref Ti, "\t");
        textview.Buffer.Insert(ref Ti, ScoreBoard[2]);
        textview.Buffer.Insert(ref Ti, "  |  ");
        textview.Buffer.Insert(ref Ti, ScoreBoard[3]);
        textview.Buffer.Insert(ref Ti, "\n");
    }
}

代码的其他部分工作正常,但是在这一部分中会发生错误。

如果我删除'async'和“ await Task.Delay(1000);”,它没有错误,但是我想每秒显示1行。

我该如何解决?

1 个答案:

答案 0 :(得分:0)

Gtk#很有气质,并且在与UI线程(主要线程)混乱的线程中不能很好地工作。另外,您不能从辅助线程更新UI(这对于所有图形工具包都是常见的)。

如果我正确理解了您的问题,则只能使用System.Threading睡眠一秒钟。问题是,如果您这样做了,那么您的应用将在整整一秒钟内都没有响应。

解决方案是主动等待直到一秒钟过去。这比等待一秒钟要精确得多,但我希望它能满足您的需求。

这是您需要的代码:

    void ActivelyWaitFor(long targetMillis)
    {
        var stopWatch = new System.Diagnostics.Stopwatch();

        stopWatch.Start();

        while( stopWatch.ElapsedMilliseconds < targetMillis ) {
            Gtk.Application.RunIteration();
        }

        stopWatch.Stop();
    }

Gtk可以运行迭代并返回(Gtk.Application.RunIteration()),在此目的很方便。在等待时间过去的同时,我们可以重复调用此命令以提供响应迅速的用户界面。

如果您对如何使用它有疑问,这是完成所需任务的窗口的全部代码。

public class MainWindow: Gtk.Window
{
    public MainWindow()
        :base(Gtk.WindowType.Toplevel)
    {
        this.Build();

        this.DeleteEvent += (o, evt) => Gtk.Application.Quit();
        this.Shown += (o, args) => this.DisplayText();
    }

    void Build()
    {
        this.TextView = new Gtk.TextView();

        this.Add( this.TextView );
    }

    void DisplayText()
    {
        string[] ScoreBoard = new string[4];
        Gtk.TextIter Ti = this.TextView.Buffer.StartIter;
        string[] Temp = {
            "1\t2\t3\t4",
            "1\t2\t3\t4",
            "1\t2\t3\t4",
            "1\t2\t3\t4",
            "1\t2\t3\t4",
            "1\t2\t3\t4",
        };

        foreach (string Line in Temp)
        {
            ScoreBoard = Line.Split('\t');

            this.ActivelyWaitFor( 1000 );

            this.TextView.Buffer.Insert(ref Ti, ScoreBoard[0]);
            this.TextView.Buffer.Insert(ref Ti, "  |  ");
            this.TextView.Buffer.Insert(ref Ti, ScoreBoard[1]);
            this.TextView.Buffer.Insert(ref Ti, "\t");
            this.TextView.Buffer.Insert(ref Ti, ScoreBoard[2]);
            this.TextView.Buffer.Insert(ref Ti, "  |  ");
            this.TextView.Buffer.Insert(ref Ti, ScoreBoard[3]);
            this.TextView.Buffer.Insert(ref Ti, "\n");
        }
    }

    void ActivelyWaitFor(long targetMillis)
    {
        var stopWatch = new System.Diagnostics.Stopwatch();

        stopWatch.Start();

        while( stopWatch.ElapsedMilliseconds < targetMillis ) {
            Gtk.Application.RunIteration();
        }

        stopWatch.Stop();
    }

    private Gtk.TextView TextView;
}

希望这会有所帮助。