【问题标题】:Modification of Utility Method to Support Multi-Threading修改实用方法以支持多线程
【发布时间】:2013-11-14 14:47:40
【问题描述】:

我已经获得了多线程应用程序,并且已经完成。此应用程序中的所有消息框都由实用程序类中的单个static 方法正确调用。这个方法是:

public static void ErrMsg(String strMsg, Exception ex = null)
{
    ...
    if (ex == null)
        MessageBox.Show(strMsg, "MyApp", MessageBoxButtons.OK, MessageBoxIcon.Warning);
    ...
}

显然,这不提供IWin32Window 所有者,当我使用此方法从后台线程池线程调用错误消息时,这会导致我出现问题。问题是在我的主表单后面显示的一个已知消息框。见:

  1. Popping a MessageBox for the main app with Backgroundworker in WPF

等。我可以将当​​前线程的SynchronisationContext 传递给ErrMsg 并执行

synchronizationContext.Send(callback => 
    MessageBox.Show("Some error message for the user"), null);

但是有 700+ 次调用此方法,其中大部分在 UI 线程上,不会导致问题。我的问题是:我怎样才能修改 ErrMsg 方法,以便我的消息框出现在当前 SynchronisationContex 的前面,而不必修改对方法的所有 700 多次调用? p>

感谢您的宝贵时间。


编辑。 @Dmitry 的想法很棒。但是,如果活动表单没有焦点或者是 MdiChild 表单,则 Form.ActiveForm 将返回 null。为了解决这个问题,我使用Application.OpenForms.Cast<Form>().Last() 来获取最后一个活动表单,无论是 MdiChild 还是其他。代码现在...

Form activeForm = Application.OpenForms.Cast<Form>().Last();
if (ex == null)
{
    activeForm.Invoke(new ShowErrMsg(text => 
        MessageBox.Show(activeForm, 
            text, 
            "UserCost",
            MessageBoxButtons.OK, 
            MessageBoxIcon.Warning)), 
        strMsg);
}

【问题讨论】:

    标签: c# multithreading winforms dialog


    【解决方案1】:

    尝试使用 Form.ActiveForm 静态属性作为 MessageBox.Show(...) 的第一个参数。还应使用线程安全调用。
    例子:

    private delegate void ShowErrMsgMethod(string text);
    
    public static void ErrMsg(String strMsg, Exception ex = null)
    {
        ...
        if (ex == null)
        {
            Form activeForm = Form.ActiveForm ?? Application.OpenForms.Cast<Form>().Last();
            activeForm.Invoke(new ShowErrMsgMethod(text => MessageBox.Show(activeForm, text, "MyApp", MessageBoxButtons.OK, MessageBoxIcon.Warning)), strMsg);
        }
        ...
    }
    

    编辑:针对打开其他表单的情况进行了改进。消除了对主窗体的引用。
    EDIT2:针对Form.ActiveForm == null 时的情况进行了改进。

    【讨论】:

    • 感谢您的回复。这看起来是一个不错的方法,我以前也想过这个;但是,除了主窗体之外的其他窗体调用此方法 - 问题是这会导致问题吗?我担心的一件事是,如果主表单启动子表单并且此表单调用ErrMsg...再次感谢我将在明天实施和测试。
    • 我已针对打开其他表单的情况更新了示例。解决方案是使用 Form.ActiveForm 静态属性作为 MessageBox 所有者。
    • 该死的。公平竞争。我明天会检查一下。一个新人的知识给我留下了深刻的印象!不知道Form 有这个静态方法。感谢您的帮助...
    • 这是个好主意,但是,如果顶部窗体没有焦点或者是 MdiChild,Form.ActiveForm 将返回 null。我已经修改了代码以适应。请参阅我编辑的问题。随意复制到您的答案中......
    • 同时使用Form.ActiveForm 是有意义的,如果一个为null - 最后一个Application.OpenFormsForm activeForm = Form.ActiveForm ?? Application.OpenForms.Cast&lt;Form&gt;().Last(); 原因:Application.OpenForms 数组的顺序未定义,并且没有保证最后一个表单现在处于活动状态。例如,您可以在Show()方法中不设置所有者,打开Form1Form2,然后在UI中切换它们。但最后一种形式永远是一样的——Form2
    猜你喜欢
    • 2021-02-23
    • 1970-01-01
    • 2012-01-30
    • 1970-01-01
    • 2023-03-03
    • 2012-02-27
    • 2011-12-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多