【问题标题】:Showing a form from a different thread显示来自不同线程的表单
【发布时间】:2016-01-12 18:31:21
【问题描述】:

所以我有一个包含这个的静态类:

    public static void ShowErrorReport(Exception e, SqlCommand sqlc = null)
    {
        try
        {
            frmErrorReport frmER = new frmErrorReport(e, SqlCommand_: sqlc);
            frmER.ShowDialog();
            frmER.Dispose();
        }
        catch (Exception f)
        {
            Debug.Print(f.ToString());
        }
    }

我希望能够从在排队后台工作程序中运行的一些与数据库相关的方法中使用它。问题是这些方法有时不知道任何 winforms 对象,因此无法使用Invoke()(据我所知)。

是否有任何其他方法可以从后台工作线程调用此过程并确保在 UI 线程上创建表单?

或者我是否会通过传递一个 winforms 对象在这些数据库方法中弄得一团糟(不期待这种可能性!)?

我对多线程还很陌生...

谢谢

【问题讨论】:

  • 这是糟糕的设计。更好地使用事件或异常。这也与多头无关。
  • 如果没有用户可以点击您的对话框,您将如何在服务中使用确切的代码?记住这一点,即使你不需要它。它仍然有助于避免此类问题。
  • @CSharpie 我没有看到 OP 说这是来自服务的地方。

标签: c# multithreading winforms backgroundworker


【解决方案1】:

我希望能够通过在排队后台工作程序中运行的一些与数据库相关的方法来使用它。问题是这些方法有时不知道任何 winforms 对象,所以使用 Invoke() 是不可能的(据我所知)。

如果您的后台代码需要与 UI 交互,您需要通过某种方式来正确地与 UI 对话。通常,为了将其抽象出来,您可以创建一个“交互服务”,您可以将其传递给您的类,然后该交互服务会调用您需要的任何 UI 技术。

public BackgroundClass
{
    public BackgroundClass(IInteractionService interactionService)
    {
        _interactionService = interactionService;
    }

    private readonly IInteractionService _interactionService;

    public static void ShowErrorReport(Exception e, SqlCommand sqlc = null)
    {
        try
        {
            _interactionService.ShowErrorReportDialog(e, sqlc);
        }
        catch (Exception f)
        {
            Debug.Print(f.ToString());
        }
    }
}

public interface IInteractionService
{
    void ShowErrorReportDialog(Exception e, SqlCommand cmd);
}

public class WinFormsInteractionService : IInteractionService
{
    public WinFormsInteractionService()
        this(SynchronizationContext.Current)
    {
    }

    public WinFormsInteractionService(SynchronizationContext syncContext)
    {
        if(syncContext == null)
            throw new ArgumentNullException("syncContext");
        _syncContext = syncContext;
    }

    private readonly SynchronizationContext _syncContext;

    public void ShowErrorReportDialog(Exception e, SqlCommand cmd)
    {
        _syncContext.Send(s => 
        {
            using(frmErrorReport frmER = new frmErrorReport(e, SqlCommand_: cmd))
            {
                frmER.ShowDialog();
            }
        });
    }
}

如果您决定从 Winforms 切换到 WPF 甚至控制台,则您的 BackgroundClass 不需要进行任何更改,您只需为您使用的任何 UI 技术创建一个实现 IInteractionService 的新类。

public class ConsoleInteractionService : IInteractionService
{
    public WinFormsInteractionService()
    {
    }

    private readonly string _showErrorReportDialogFormatString = //...

    public void ShowErrorReportDialog(Exception e, SqlCommand cmd)
    {
        Console.WriteLine(_showErrorReportDialogFormatString, e, cmd);
        Console.WriteLine("Press enter to continue");
        Console.ReadLine();
    }

}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-15
    • 1970-01-01
    • 2015-02-25
    相关资源
    最近更新 更多