gpt4 book ai didi

c# - 表格 "Not responding"如果之前没有显示

转载 作者:行者123 更新时间:2023-11-30 17:59:29 26 4
gpt4 key购买 nike

我有一个监视目录更改的应用程序。创建文件(日志文件)时,它会分析其内容,将结果写入表单(已经存在并已初始化,尽管当前可能隐藏),最后将此表单显示给用户。

应用程序启动时,任务栏中只会显示一个图标。 main 方法只是在任务栏中创建图标并初始化监视/分析和控制带有结果的表单的类。

public static void Main(string[] args) {
NotificationIcon notificationIcon = new NotificationIcon();
notificationIcon.notifyIcon.Visible = true;
if (notificationIcon.Init()) {
MainForm = ResultForm.GetInstance();
Application.Run();
}
}

“ResultForm”是我刚才提到的类,有以下与问题相关的方法:

public static ResultForm GetInstance() {
// _this is an attribute from the class. Is used to work always
// with just one instance of the classe
if (_this==null)
_this= new ResultForm();

return _this;
}

private ResultForm() {
// initialization of the GUI form
InitializeComponent();

[...]

// watcher for the log files
logsWatcher= new FileSystemWatcher(LOGFILES_FOLDER);
logsWatcher.Created += new FileSystemEventHandler(NewFile);
logsWatcher.EnableRaisingEvents=true;
logsWatcher.SynchronizingObject = this;
}

private void NewFile (object source, FileSystemEventArgs e) {
// make sure the file is of the correct type
[...]
// perform some analysis on the file
[...]
// update the contents in the form (some TreeViews and labels)
[...]

// show the form to the user
_this.Show();
}

现在问题来了。如果应用程序启动,分析了一个文件,还没有显示主窗体,分析完成后会显示为“Not responding”,虽然一切都已经完成了。如果之后创建了一个新文件,它将被成功分析,尽管表单将保持这种“未响应”状态。

但是,如果表单自应用程序启动后至少打开过一次(例如,您双击图标,显示表单,然后您将其关闭(或保持打开状态,这无关紧要)) ,一切都会顺利进行。

作为一种变通方法,我可以使用以下两行修改 main(在 Run() 方法之前),这样在任何文件到来之前该表单至少会显示一次:

MainForm.Show();
MainForm.Hide();

(我将它隐藏起来,因为在执行分析或用户明确单击该图标之前它不应该是可见的。)除此之外,程序没有区别:完成的工作是相同的,一旦完成所有操作,表格总是会显示。我已通过调试器确保在执行过程中已到达方法的末尾。

如果没有提到的解决方法,我该如何解决这个问题?

我已尝试使用 Application.DoEvents() 或类似于 this one 的代码块为分析创建线程.在最好的情况下,表单会正确显示其所有内容,但仍处于“未响应”状态。我还尝试只在方法中保留 Show() 调用,结果完全相同,这告诉我这不是重负载的问题,而是我可能做错了什么。

编辑由于@thecoon 提出要求,我上传了一个重现该问题的小项目。它已通过 SharpDevelop 完成,以防您也使用它。--> http://dl.dropbox.com/u/1153417/test.zip

在 Main() 方法中有一个小的解释。

最佳答案

我强烈怀疑这是一个线程问题,一个由您如何启动 ResultForm 以及如何设置 FileSystemObjects synchronization object 引起的问题.

同步对象有效地选择线程来编码更新。在这种情况下,它也是您试图在其上显示 GUI 的线程,因此您可能遇到了一个很好的旧阻塞操作,或者可能只是有大量文件系统事件导致您的线程来回上下文切换迅速。

作为初学者,试试这个:

public static void Main(string[] args) {
NotificationIcon notificationIcon = new NotificationIcon();
notificationIcon.notifyIcon.Visible = true;
if (notificationIcon.Init()) {
MainForm = new ResultForm();
Application.Run(MainForm);
}
}

请注意,我们现在将 ResultForm 直接编码到 UI 线程。

并以这种方式更改 ResultForm(也没有必要将其设为单例):

public ResultForm() {
// initialization of the GUI form
InitializeComponent();

[...]
this.Load += ResultForm_Load;
}


protected void ResultForm_Load(object sender, EventArgs e)
{
// watcher for the log files
logsWatcher= new FileSystemWatcher(LOGFILES_FOLDER);
logsWatcher.Created += new FileSystemEventHandler(NewFile);
logsWatcher.EnableRaisingEvents=true;
//Don't set the synchronization object - now all events from the FileSystemWatcher will be marshalled on a background thread
Visible = false; //Hide the form if you want or minimize to tray or similar.
}

private void NewFile (object source, FileSystemEventArgs e) {

if(InvokeRequired){
//Ensures the file system events are marshalled back to the GUI thread
Invoke(new MethodInvoker(() => {NewFile(source, e);}));
return;
}

// make sure the file is of the correct type
[...]
// perform some analysis on the file
[...]
// update the contents in the form (some TreeViews and labels)
[...]

// show the form to the user
Show(); //or Visible = true;
}

通过不将 FileSystemWatcher 上的同步对象设置为表单,您可以确保所有文件系统事件编码都将在 ThreadPool 线程中发生。当引发新事件时,我们只需记住通过检查 InvokeRequired 并在必要时调用表单的 Invoke 方法来编码回 UI 线程。

更新

主要原因是,通过直接调用 MainForm.Show 或通过 Application.Run(MainForm),您将表单推送到消息循环所在的线程上。

如果您使用原始代码运行应用程序,当调用 NewFile 时,Application.MessageLoop 为 false。

如果您使用变通方法或显示应用程序的标准方式,按照我的示例,Application.MessageLoop 为真。

我最好的猜测是表单死锁是因为 FileSystemWatcher(它在原始示例中使用表单作为同步对象,这实际上意味着它在表单上调用 BeginInvoke) .但是,它也可能是各种各样的其他问题; Form.Show() 实际上卡在方法 FPushMessageLoop 上 - 它陷入无限循环。

@HansPassant 或@HenkHolterman 都围绕这些问题发表了大量文章 - 请参阅 https://stackoverflow.com/a/3833002/1073107例如。请注意,如果您在启动时显示启动画面或类似画面,则所有初始化都按预期工作,并且 NewFile 成功完成;简而言之,如果您希望流程正常运行,您必须在应用程序启动时显示一些内容。我不认为这是一件坏事;例如,用户可以看到应用程序已经启动并正在托盘中运行,您可以确定不会遇到此问题。

关于c# - 表格 "Not responding"如果之前没有显示,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11191864/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com