System.AccessViolationException occurs on TextView.Buffer

可紊 提交于 2019-12-11 04:58:51

问题


I am trying to show some text on C#, one line per second, using Gtk# GUI. the text is on .txt file, and it has 4 integers at every line.

but when I compiled it at DragonFly BSD, the first one or two lines are showed perfectly on textbox but the program halts, and I've got SIGABRT and SIGSEGV errors.

so I've compiled same code at Windows, and it has this error: Exception of 'System.AccessViolationException' or something like that.

I've checked "Allow unsafe codes", but the result was same.

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

The other parts of code works perfectly, but in this part, the error occurs.

If I delete 'async' and "await Task.Delay(1000);", it doesn't have error but I want to display it 1 lines per second.

How can I solve it?


回答1:


Gtk# is quite temperamental and does not work very well with threads messing with the UI thread (the main one). Also, you cannot update the UI from a secondary thread (this is common for all graphic toolkits).

If I understood your problem correctly, you could only just use System.Threading in order to sleep for a second. The problem is, if you did that, your app would be unresponsive for that whole second.

The solution is to actively wait until a second has passed. This is less exact, than waiting for exactly a second, but I hope it will meet your needs.

Here is the code you need:

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

        stopWatch.Start();

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

        stopWatch.Stop();
    }

Gtk can run an iteration and return (Gtk.Application.RunIteration()), which is handy for the purpose here. We can call repeately that in order to offer a responsive user interface, while we wait for the time to pass.

And here is the whole code for a window doing the task you need, in case you have doubts about how to use it.

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

Hope this helps.



来源:https://stackoverflow.com/questions/56514683/system-accessviolationexception-occurs-on-textview-buffer

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!