System.AccessViolationException происходит в TextView.Buffer - PullRequest
1 голос
/ 09 июня 2019

Я пытаюсь показать какой-нибудь текст на C #, одну строку в секунду, используя Gtk # GUI.текст находится в файле .txt, и в каждой строке по 4 целых числа.

, но когда я скомпилировал его в DragonFly BSD, первые одна или две строки отлично отображаются в текстовом поле, но программа останавливается, и яЯ получил ошибки SIGABRT и SIGSEGV.

, поэтому я скомпилировал один и тот же код в Windows, и у него есть эта ошибка: исключение «System.AccessViolationException» или что-то в этом роде.

I 'мы проверили «Разрешить небезопасные коды», но результат был таким же.

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 голосов
/ 25 июня 2019

Gtk # довольно темпераментный и не очень хорошо работает с потоками, связанными с потоком пользовательского интерфейса (основным). Кроме того, вы не можете обновить пользовательский интерфейс из вторичного потока (это является общим для всех графических инструментов).

Если я правильно понял вашу проблему, вы можете просто использовать 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;
}

Надеюсь, это поможет.

...