System.AccessViolationException 发生在 TextView.Buffer

System.AccessViolationException occurs on TextView.Buffer

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

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

所以我在 Windows 编译了相同的代码,但它有这个错误: 'System.AccessViolationException' 的异常或类似的东西。

我检查过"Allow unsafe codes",但结果是一样的。

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 行。

我该如何解决?

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 可以 运行 一次迭代和 return (Gtk.Application.RunIteration()),这对于这里的目的来说很方便。我们可以重复调用它以提供响应式用户界面,同时等待时间过去。

这里是 window 执行您需要的任务的完整代码,以防您对如何使用它有疑问。

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;
}

希望对您有所帮助。