如何停止显示多个对话框?

时间:2010-07-14 07:46:06

标签: .net vb.net winforms

我有一个非常讨厌的问题,我正试图找到最简单的解决方案,但我似乎一直在使它复杂化。

我的程序使用ShowDialog函数显示一个自定义对话框(我使用New构造函数创建此表单),但是当我的程序在对话框中等待输入时,我的程序继续运行其他代码,(我假设已启动从其他消息,但我仍然无法找到关于此的良好信息,所以除了这个主题,任何人都有关于此的参考),并到达同一点,在那里显示对话框并显示它。所以我最终得到了大量的对话框。

我的目标是防止过多的对话框。如果程序到达此对话框启动点,我希望它等待/暂停,直到第一个对话框完成。

我考虑过线程解决方案,后台工作者,各种想法,但它们似乎使事情变得复杂,我实际上并没有修复它。

有谁知道如何防止这种情况发生?

非常感谢您的帮助。 感谢

6 个答案:

答案 0 :(得分:1)

在我看来,你的代码中有一些非常难看的bug!我首先关注修复这个bug。执行此操作的简单方法是在打开对话框的行上设置断点。第二次点击该行时(第一个对话框仍处于打开状态),查看该点的堆栈跟踪并检查所有活动线程(查看线程和查看堆栈窗口)以找出问题的原因。

此外,更改代码以打开模式对话框窗口,其中父窗口必须是所有者。模态对话框窗口将停止执行并阻止父窗口处理用户输入(这可能导致此行为)。

修改

从您的评论中我收集到您有几个无法控制的线程,并且您希望一次一个线程来访问消息框代码。使用线程时,有几个可用的同步原语。扩展每一本书都需要一本书(你可以尝试Concurrent Programming on Windows,一本书在其结构中有一些缺陷时是彻底的),知道正确的一本书需要你的代码知识。

也就是说,你可能希望做一些类似下面的事情,使用一个至少阻止其他线程访问代码的Mutex(意思是:它会将它们置于挂起状态直到Mutex被释放)。如果要阻止弹出框多次显示,请添加一个静态布尔标志变量(或在弹出窗体“仅显示一次”上添加一个复选框)。 Mutex plus flag解决了两个问题:只有一个线程会运行该代码,代码只会运行一次。

// as static class variable, create a mutex
private static Mutex dialogMutex = new Mutex();

// a static flag preventing the dialog box to show more than once
// (you may wish to resolve this differently, depending on req's)
private static boolean dialogIsShownOnce = false;

public static void ShowDialogBox()
{
    // Wait until it is safe to enter, this makes the current thread 
    // the exclusive user of this code and other threads may only enter
    // after the current thread finishes.
    dialogMutex.WaitOne();

    // depending on your requirements, you may not want this
    // must come _after_ WaitOne to prevent entering before another
    // thread that entered hasn't yet changed this variable
    if(dialogIsShownOnce)
       return;


    // show your dialog box as a modal box 
    // if you are unsure: add a breakpoint just after the ShowDialog 
    // it should only be hit _after_ you dismiss the dialog box
    yourForm.ShowDialog();

    // set the flag, or the counter, or whatever you wish:
    dialogIsShownOnce = true;

    // Release the Mutex, this will remove the "roadblock" and allow
    // other threads to enter this piece of code
    dialogMutex.ReleaseMutex();
}

上面的代码未经过测试,应该被视为如何解决此问题的提示。有很多方法可以解决这个问题,但我认为上述方法可能正是您所需要的。

答案 1 :(得分:1)

我可能在这里误解了这个问题,但您是否尝试过以下方法:

 Dim frmFindForm As dlgPromptForm

 frmFindForm = New dlgPromptForm()     

 If (frmFindForm.ShowDialog(Me) = DialogResult.OK) Then
    'Do something because they hit ok, if needed
 Else
    'Do something else because they didn't hit ok, if needed
 End If`

要使其工作,您需要确保当用户点击按钮时,对话框窗体设置DialogResult属性。 (例如:单击“确定”按钮,单击“DialogResult = System.Windows.Forms.DialogResult.OK”)

这会导致程序停在if,直到用户按下对话框上的其中一个按钮。

这可能与您所寻找的内容有关,但我真的无法从您提供的信息中得知。

答案 2 :(得分:0)

我会看到两种可能性: 如果您在一个位置打开对话框,而不是在那里更改它不会调用对话框,而是某种堆栈,并且您可以检查对话框何时关闭,如果堆栈上还有剩余的东西。

或者,如果可能,在打开第一个对话框时更改所有者窗口,该窗口将传递给对话框。并隐藏。 如果所有者被隐藏 - >对话框被隐藏。

答案 3 :(得分:0)

在关闭对话框之前,使用ShowDialog()绝不应该让其余的代码执行。所以,我的猜测是您的代码存在问题。正如Abel建议的那样,您应该使用断点并跟踪代码。 我的另一个猜测是,其他对话框是从原始对话框中启动的,并且它会以递归方式继续发生。

如果您在此处发布代码,将会更容易提供帮助。

答案 4 :(得分:0)

我只想创建一个表单范围boolean say

DIM DisplayedMSGBOX as boolean = false

(如果线程在单独的表单上运行,只需将此布尔值设为全局)

public DisplayedMSGBOX as boolean = false)

然后在显示消息框的位置我会放置

如果没有显示MSGBOX那么

msgbox(“这将是你的msgbox”)

ENDIF

在某些时候,如果你想重置msgbox再次使用

DisplayedMSGBOX = false

现在重置了msgbox。

答案 5 :(得分:0)

是的,这可能来自您的代码,正如Abel所建议的那样,但也有一个非常愚蠢的Visual Studio Designer错误,这也会导致只需单击即可打开双重甚至三个对话框。

您知道如何双击Visual Studio Designer中的元素或按钮,它会在代码中为它创建一个空子(如果没有找到现有代码)?嗯,在Visual Studio / Basic中有一个非常恼人的错误,双击一个新按钮(有时)不会创建一个新的子按钮,而是随意且莫名其妙地将该按钮的点击事件粘贴到现有的潜艇上,而无需您的意愿或同意。如果你不注意并忘记删除垃圾点击事件,你最终会意外地同时启动几个潜艇。

我在以下项目中有一个例子:

Private Sub btnOptionsThemeLB_HK_Click(sender As System.Object, e As System.EventArgs) Handles btnOptionsThemeLB_HK.Click, btnOptionsThemeLB_Back2.Click, btnOptionsThemeLB_Back5.Click, btnOptionsThemeLB_Back4.Click
    ColorMeNow.Color = tempOptionsThemeLB_HK
    ColorMeNow.ShowDialog()
    Me.btnOptionsThemeLB_HK.BackColor = ColorMeNow.Color
    txtbOptionsThemeLB_HK_Red.Text = exRed(ColorMeNow.Color).ToString
    txtbOptionsThemeLB_HK_Green.Text = exGreen(ColorMeNow.Color).ToString
    txtbOptionsThemeLB_HK_Blue.Text = exBlue(ColorMeNow.Color).ToString
    txtbOptionsThemeLB_HK_Hex.Text = exHexFromColor(ColorMeNow.Color)
    tempOptionsThemeLB_HK = ColorMeNow.Color
    'My.Settings.Save()
End Sub

这里的罪魁祸首可以在子申报行中找到。

我应该有:

  Private Sub ... Handles btnOptionsThemeLB_HK.Click

但相反,我有:

  Private Sub ... Handles btnOptionsThemeLB_HK.Click, btnOptionsThemeLB_Back2.Click, btnOptionsThemeLB_Back5.Click, btnOptionsThemeLB_Back4.Click

所有这些子开放颜色选择器对话。 Back2,Back4和Back5被设计师自动添加到Sub btnOptionsThemeLB_HK_Click,我忘了删除它们。在运行时,当我单击Back2,Back4和Back5按钮时,它们产生了两个对话框(属于它们的对话框和btnOptionsThemeLB_HK_Click的对话框)。删除不需要的点击事件将解决此问题。

更新: 似乎如果您想通过拖动和复制现有按钮来添加新按钮,并且如果正在复制的现有按钮已经与现有Sub关联,则Visual Basic将假设您希望复制它的点击事件,并为您复制的每个按钮添加一个新的点击事件给所述Sub。