我接受MUG4N对这个问题的回答,我也想回应针对它提出的一些批评。
ChrisF说:
...您无法直接从后台线程进行UI调用。
这是一个一揽子声明,并非100%正确。我只想指出一些事实:
如果设置Control.CheckForIllegalCrossThreadCalls = false
,您实际上可以通过>进行用户界面调用。 “Ack!”我听到你说。 “不要永远这样做!”是的,是的 - 但是为什么?答案:因为有时这会破坏记忆。
System.Windows.Forms
中的控件类不是编写为线程安全的,因此有时从后台线程更新它们会破坏内存。但如果只有有时发生而不是总是,那么这告诉我的是它不是调用UI代码本身 ,而是可能导致异常的UI代码可能不安全的碰撞 。
为了强化第1点,请考虑以下因素:从后台线程调用UI代码的“安全”方法是使用Control.Invoke
或Control.BeginInvoke
来实现,对吧? 但 是一个用户界面调用;如果我们要从非GUI线程更新GUI,那么它只是我们应该做的 UI调用。我的意思是,显然,它不是简单地从外部线程调用Control
对象上的“任何”方法会导致混乱(如果是这种情况,那么我们甚至不能调用{{1而且我们会完全被困住)。同样,这是单独的UI调用的潜在冲突,这些调用不能同时安全地发生,这将证明具有破坏性。
牢记以上两点,请问自己:为什么从非GUI线程调用Invoke
会不安全?创建并显示完全独立的MessageBox.Show
;它的属性不以任何方式与任何其他现有GUI对象交互;事实上,它不能以任何方式以任何方式以任何方式访问 ,除了一个:来自调用线程,它访问其Form
属性(并且仅通过DialogResult
方法的返回值)。
继续前进。康拉德阿尔布雷希特说:
...鉴于断言Show()在Dan的ref'd主题中设置了自己的消息泵,(这没有证实,但我不能反驳)......
这是一个完全公平的观点(虽然我个人非常尊重Jared Par,但我通常不会怀疑怀疑他说的话)。在任何情况下,通过Reflector查看Show
方法都可以看到此代码段:
MessageBox.Show
进一步了解Application.BeginModalMessageLoop();
try
{
result = Win32ToDialogResult(SafeNativeMethods.MessageBox(new HandleRef(owner, zero), text, caption, type));
}
finally
{
Application.EndModalMessageLoop();
UnsafeNativeMethods.ThemingScope.Deactivate(userCookie);
}
方法可以看出这一点:
Application.BeginModalMessageLoop
依次为ThreadContext.FromCurrent().BeginModalMessageLoop(null);
:
ThreadContext.FromCurrent
我对这些较低级别的Windows构造知之甚少,无法完全理解这段代码,但在我看来,这似乎是Jared在我的旧评论中引用的答案的确切证据(对于好奇的读者: Does MessageBox.Show() automatically marshall to the UI Thread?)。
所以,是的。我完全赞同MUG4N的这一点。
(如果有人能够令人信服地说我在这里仍然错了,请说出来。虽然我觉得我为什么相信MUG4N是对的,但我显然不是100%肯定的。)< / p>
通常,您只是想通知用户发生了某些事情,但实际上并不需要来自他们的任何输入。在这种常见情况下,我有时会看到这样的代码:
// [Reflector shows that currentThreadContext is a ThreadStatic member. -Dan]
if (currentThreadContext == null)
{
currentThreadContext = new Application.ThreadContext();
}
return currentThreadContext;
众所周知,此代码只会弹出一个小窗口,只显示确定按钮。现在就是这样的事情:这个代码块(UI线程)。但在绝大多数情况下,在我看来,如果你只有有一个 OK 按钮,那么几乎不需要阻止。 (通常阻止用户接收某些输入的目的不是?如果用户的仅选择是“OK”,在这种典型的情况下,是不是阻止相当无意义?)
显然,我可以编写自己的小形式,它基本上完全符合MessageBox.Show("Something has occurred", "Something", MessageBoxButtons.OK);
的作用,除了它不返回任何内容(没有MessageBox.Show
)并且不会阻止。但我只是想知道这样的事情是否存在,我不知道。
答案 0 :(得分:11)
您需要使用多线程来执行此任务,其中一个线程(主线程)将执行处理,另一个线程将用于显示消息框。
答案 1 :(得分:7)
如何在应用中添加NotifyIcon并显示balloon tip呢?缺点是通知会在短时间后消失,但如果用户不需要采取行动,这可能是最好的。
this question还有更多建议。
答案 2 :(得分:2)
我会尝试直接从Win32 API调用MessageBox函数,例如:
using System.Runtime.InteropServices;
[DllImport("User32.dll")]
public static extern int MessageBox(int h, string m, string c, int type);
尝试使用null句柄和APPLMODAL类型。这可能有用。
答案 3 :(得分:0)
这是一个老问题,但是nevertheles ......
1)导入IWshShell('Windows脚本宿主对象模型')
Dim wsh As New IWshRuntimeLibrary.WshShell wsh.Popup(String.Concat(Me.GetType.FullName,vbCrLf,_ Application.ExecutablePath),0.75,“Title”,MessageBoxButtons.OKCancel或MessageBoxIcon.Question)
...延