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;
}
希望对您有所帮助。
我正在尝试使用 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;
}
希望对您有所帮助。