为啥一个代码路径会立即在顶部显示表单,而另一个则不会?
Posted
技术标签:
【中文标题】为啥一个代码路径会立即在顶部显示表单,而另一个则不会?【英文标题】:Why does one code path show the form on top immediately while the other doesn't?为什么一个代码路径会立即在顶部显示表单,而另一个则不会? 【发布时间】:2011-08-15 13:58:02 【问题描述】:我正在维护一个使用 Castle Windsor 作为框架的 C# .net 程序。它还使用 Skincrafter 来装饰表格。
在其中,我们具有检测 USB 设备上是否存在文件并生成另一种形式来处理它的功能。当 Windows 引发 USB 事件或用户按下强制重新检查的按钮时,软件会检查文件。
当用户强制重新检查时,如果找到文件,则表单会出现在主表单的顶部,并由 Skincrafter 装饰。如果引发 USB 事件,则生成表单,但不会出现在顶部(必须在任务栏中单击它才能看到它)并且不是 Skincrafter 修饰的。
两种检测文件的方法都达到了相同的功能,它告诉程序的另一部分产生处理文件的表格。我在调试时发现的唯一区别是强制重新检查方法使用主线程,而 USB 事件方法有它自己的子线程,该子线程通过显示的表单。
是单独的线程导致 Windows 不在顶部生成表单(并且可能被 Skincrafter 忽略)还是可能存在其他问题?
如果需要,我可以发布代码,但代码路径除了调用文件检查的方法和数据相同外,其他路径相同。
编辑 - 代码:
这是我制作的一个简单的重建。将 System.Management 添加到引用中的新 WinForms 项目。只需制作一个带有按钮的表单(FormStartPosition 设置为 CenterScreen)并使用以下代码:
public partial class Form1 : Form
private ManagementEventWatcher _eventWatcher = null;
int devices = 0;
public Form1()
InitializeComponent();
WqlEventQuery q = new WqlEventQuery();
q.EventClassName = "__InstanceOperationEvent";
q.WithinInterval = new TimeSpan(0, 0, 3);
q.Condition = @"TargetInstance ISA 'Win32_USBControllerDevice' ";
_eventWatcher = new ManagementEventWatcher(q);
_eventWatcher.EventArrived += new EventArrivedEventHandler(UsbEventArrived);
_eventWatcher.Start(); // Start listen for events
private void UsbEventArrived(object sender, EventArrivedEventArgs e)
if(System.Environment.GetLogicalDrives().Length - devices != 0)
ShowThingy();
devices = System.Environment.GetLogicalDrives().Length;
private void button1_Click(object sender, EventArgs e)
ShowThingy();
private void ShowThingy()
Form form2 = new Form();
form2.Size = new Size(50, 50);
form2.StartPosition = FormStartPosition.CenterParent;
form2.TopMost = true;
form2.ShowDialog();
运行并插入 USB 设备,form2 表单应出现在主表单后面。
这似乎不会每次都重现问题。但是我第一次插入 USB 设备时似乎总是在第一个形式之后创建第二个形式。每次单击按钮都会在顶部生成第二个表单。
我应该注意我运行的是 Windows 7。
【问题讨论】:
请贴一些代码,否则是猜测。另外,我不明白温莎与温莎有什么关系,你能解释一下吗? 我已将代码附在最后。我提到了温莎,因为我不知道这是否会导致线程出现问题,所以这是一个相关的细节。 似乎有太多不相关的代码......你能把它缩小到一个独立的失败测试吗? 创建了一个新项目来简化它。正如最后指出的那样,它似乎只是第一次未能登上榜首。 【参考方案1】:您没有设置模态窗口的所有者,默认是活动窗口(可能不是您的主窗口)。
如果您使用 ShowDialog 的重载来获取所有者,会发生什么情况?
form2.ShowDialog(this);
如果这不起作用,则表明存在线程问题的强烈气味。您可以尝试将 USB 事件处理程序更改为在表单上使用 Invoke 吗?
【讨论】:
使用 ShowDialog(this) 可以完全阻止该框出现。我尝试过使用 BeginInvoke,它适用于该示例,但不适用于我的实际程序。在我的程序中强制调用实际上并没有调用委托代码,这很奇怪。以上是关于为啥一个代码路径会立即在顶部显示表单,而另一个则不会?的主要内容,如果未能解决你的问题,请参考以下文章
在 Visual Studio 的设计视图中打开表单 (.cs) 会立即显示未保存的更改