为啥一个代码路径会立即在顶部显示表单,而另一个则不会?

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) 会立即显示未保存的更改

为啥我的 textarea 的占位符没有出现?

为啥我的子视图没有显示在堆栈顶部?

为啥 iloc() 的一种使用会给出 SettingWithCopyWarning,而另一种则不会?

为啥一个类变量没有在列表理解中定义,而另一个是?

调用 layoutIfNeeded 后视图未立即显示