C# 向 FormClosing 事件添加代码禁用 MdiParent 上的 X

发布于 2024-10-10 19:40:17 字数 743 浏览 2 评论 0原文

我有两个后台线程和一个用于处理 WinForms 应用程序上运行的最小化的线程。当程序关闭时,我使用这个方法。

private void MyForm_Closing(object sender, FormClosingEventArgs e)
    {
        if(labelsUpdaterThread.IsAlive == true)
            labelsUpdaterThread.Abort();
        if(printNotifyThread.IsAlive == true)
            printNotifyThread.Abort();
        if(minimizeThread.IsAlive == true)
            minimizeThread.Abort();
    }

labelsUpdaterThread 和 printNotifyThread 始终运行。正如您可能猜到的那样,MinimizeThread 仅在最小化父窗体时运行。这是我的问题:

当在上面的方法中调用 thread.abort 方法时,我的 MdiParent 表单右上角的“X”不执行任何操作。点击它没有任何效果。

当在我的上述方法中未调用 thread.abort 方法时,关闭 MdiParent 有时会引发异常,因为线程仍在尝试访问 MdiParent 上不再可用的资源,即使它们是后台线程!

我不确定为什么会发生这种情况,对我来说没有多大意义。预先感谢您的任何帮助!

I have two background threads and a thread to handle minimization running on my WinForms Application. When the program closes, I use this method.

private void MyForm_Closing(object sender, FormClosingEventArgs e)
    {
        if(labelsUpdaterThread.IsAlive == true)
            labelsUpdaterThread.Abort();
        if(printNotifyThread.IsAlive == true)
            printNotifyThread.Abort();
        if(minimizeThread.IsAlive == true)
            minimizeThread.Abort();
    }

labelsUpdaterThread and printNotifyThread run all the time. MinimizeThread, as you might guess, only runs when the parent form is minimized. Here's my problem:

When the thread.abort methods are called in my above method, the "X" on the top right of my MdiParent form doesn't do anything. Clicking it has no effect.

When the thread.abort methods are NOT called in my above method, closing the MdiParent will sometimes throw exceptions because the Threads are still trying to access resources on the MdiParent that are no longer available, even though they are background threads!

I'm unsure as to why this is happening, doesn't make much sense to me. Thanks in advance for any help!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

掩饰不了的爱 2024-10-17 19:40:17

我同意Paul Alexander的回答 因为您永远不应该调用Thread.Abort,这是一种处理同步的可怕方法。

此外,这里的关注点分离非常糟糕。线程不应直接访问表单中的资源。两者之间应该存在某种抽象/共享状态,由双方(线程和表单,因此请确保实例线程安全)修改和读取。

也就是说,如果您无法在 Close 方法中进行这些更改,请在另一个线程中调用 Thread.Abort 方法,并在每个方法周围使用 try/catch 语句。至少在某个地方记录错误。

在另一个线程上执行对 Thread.Abort 的调用时,您不会阻塞 UI 线程,因为对 Thread.Abort 的调用不能保证是瞬时的,并且阻塞 UI 线程将导致 X 变灰,而 UI 线程无法处理 Windows 消息(这也有助于指导您更好地分离关注点)。

但是,您应该抽象出表单和线程之间共享的资源,并提供适当的取消机制。

如果您将资源抽象到共享状态的类,那么您的表单不必在关闭时执行任何操作,线程调用堆栈具有对具有状态的对象的引用,然后您可以在这些线程上调用 abort不用担心表单和线程共享任何内容。

从那里,您可以引入适当的合作取消机制(合作取消,该任务.NET 4.0 支持(如果您可以使用)。

I agree with Paul Alexander's answer in that you should never call Thread.Abort, it's a horrible way to handle synchronization.

Additionally, you have a horrible separation of concerns here. The threads should not access resources in the form directly. There should be some sort of abstraction/shared-state in between, which is modified and read by both sides (the thread and the form, so make sure to make the instance thread-safe).

That said, if you couldn't make those changes then in the Close method, call the Thread.Abort methods in another thread with a try/catch statement around each. Log the error(s) somewhere at least.

In performing the calls to Thread.Abort on another thread, you don't block the UI thread, as the calls to Thread.Abort are not guaranteed to be instantaneous, and blocking the UI thread will cause the X to be greyed out while the UI thread cannot process Windows Messages (it also helps to guide you to a better separation of concerns).

However, you should move to abstract out the resources that are shared between the form and the thread, as well as provide a proper cancellation mechanism.

If you abstract out the resources to a class that shares the state, then your form doesn't have to do anything on close, the thread call stacks have a reference to the object that has the state and you can then call abort on those threads without worrying about the form and the threads sharing anything.

From there, you can then introduce a proper cooperative cancellation mechanism (cooperative cancellation, which Task supports in .NET 4.0, if that's available to you).

蓝咒 2024-10-17 19:40:17

Abort 调用可能会引发异常。在调用 abort 之前,请确保指针有效并且线程仍然有效(未释放)。

并且,在 Visual Studio 中,打开 Debug\Exceptions... 并在“抛出”列中设置所有异常的检查,以便您在出现问题时看到。

The Abort calls are probably throwing exceptions. Make sure that the pointers are valid and threads are still valid (not disposed) before calling abort.

And, in visual studio, open Debug\Exceptions... and set a check in the 'thrown' column for all exceptions so you see when something goes wrong.

拥有 2024-10-17 19:40:17

首先,删除对 .Abort() 的调用,并且不再使用它们。线程永远不应该通过调用 Abort 来终止。它基本上会使您的线程崩溃,并且不会给它机会正确释放任何资源或释放任何系统句柄。相反,创建一个 ManualResetEvent 并在线程中检查它。当事件设置后,它们应该终止。

Thread1

while( ! _stopEvent.WaitOne(0) )
{
  ...do my thready work

}

然后在关闭时

private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
  _stopEvent.Set();
  labelsUpdaterThread.Join();
  ...
}

如果您不关心线程是否在应用程序存在时正确终止,只需设置 IsBackground = true ,它们将在应用程序退出时自动终止。

First, Delete the calls to .Abort() and never use them again. Threads should never be terminated by calling Abort. It basically crashes your thread and doesn't give it a chance to release any resources properly or free any system handles. Instead create a ManualResetEvent and check that in your threads. When the event is set, they should terminate.

Thread1

while( ! _stopEvent.WaitOne(0) )
{
  ...do my thready work

}

Then in closing

private void MyForm_Closing(object sender, FormClosingEventArgs e)
{
  _stopEvent.Set();
  labelsUpdaterThread.Join();
  ...
}

If you don't care if the threads terminate properly on application exist, just set IsBackground = true and they'll be terminated automatically when the application exits.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文