21

我有两个 C# winform (.NET 4.0) 表单,每个表单都连续运行单独但相似的自动化任务。分开是因为它们是不同的流程/工作流,但它们的操作方式足够相似以在项目中共享相同的资源(方法、数据模型、程序集等)。

两种形式都是完整的,但现在我不确定如何运行程序,以便每个窗口在启动时打开并独立运行。该程序在部署时将“永远在线”。

这可能看起来有点基础,但我的大部分开发经验都是 Web 应用程序。线程/等对我来说还是有点陌生​​。我已经研究过,但我发现的大多数答案都与用户交互和顺序用例有关——这只是一个系统不断运行两个不同的进程,它们需要独立地与世界交互。

我发现的潜在解决方案可能涉及多线程,或者某种 MDI,或者一些人建议使用 DockPanelSuite(虽然在超级企业环境中,下载第三方文件说起来容易做起来难)。

static class Program
{
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        // Rather than specifying frmOne or frmTwo,
        // load both winforms and keep them running.
        Application.Run(new frmOne());
    }
}
4

3 回答 3

42

您可以创建一个新ApplicationContext的来表示多个表单:

public class MultiFormContext : ApplicationContext
{
    private int openForms;
    public MultiFormContext(params Form[] forms)
    {
        openForms = forms.Length;

        foreach (var form in forms)
        {
            form.FormClosed += (s, args) =>
            {
                //When we have closed the last of the "starting" forms, 
                //end the program.
                if (Interlocked.Decrement(ref openForms) == 0)
                    ExitThread();
            };

            form.Show();
        }
    }
}

使用它,您现在可以编写:

Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new MultiFormContext(new Form1(), new Form2()));
于 2013-03-08T18:45:30.773 回答
10

如果你真的需要两个窗口/窗体在两个单独的 UI 线程上运行,你可以这样做:

static class Program
{
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);

        var thread = new Thread(ThreadStart);
        // allow UI with ApartmentState.STA though [STAThread] above should give that to you
        thread.TrySetApartmentState(ApartmentState.STA); 
        thread.Start(); 

        Application.Run(new frmOne());
    }

    private static void ThreadStart()
    {
        Application.Run(new frmTwo()); // <-- other form started on its own UI thread
    }
}
于 2013-03-08T18:44:37.897 回答
1

假设

不需要这两个不同的进程,您只使用这两个进程,因为您希望拥有两种不同的表单,并且希望能够保持应用程序运行,直到两个表单都退出。

另一种解决方案

依靠Form.Closed事件机制。您可以添加一个事件处理程序,它允许您指定表单关闭时要执行的操作。例如,当两者都退出应用程序表单都关闭

就一些代码而言

    public Form1()
    {
        InitializeComponent();

        _form2 = new Form2();
        _form2.Show(this);

        this.Closed += Form1Closed;
        _form2.Closed += Form2Closed;
    }

    protected override void OnFormClosing(FormClosingEventArgs e)
    {
        e.Cancel = true;
        Hide();
        Form1Closed(this, new EventArgs());
        base.OnFormClosing(e);
    }

    private void Form1Closed(object sender, EventArgs eventArgs)
    {
        form1IsClosed = true;

        TryExitApplication();
    }

    private void Form2Closed(object sender, EventArgs eventArgs)
    {
        _form2IsClosed = true;

        TryExitApplication();
    }

    private void TryExitApplication()
    {
        if (form1IsClosed && _form2IsClosed)
        {
            Dispose();
            Application.Exit();
        }
    }

请注意,这应该被重构以使其成为更好的解决方案。


更新

Servy提供的评论使我修改了这个“应该是简单的解决方案”,指出他的解决方案比这个解决方案要好得多。由于支持我留下答案,因此我将使用此答案,我还将解决在寻求此解决方案时开始出现的问题:

  • 取消关闭事件
  • 从一个事件重新路由到另一个事件
  • 强制调用Dispose
  • 正如Servy指出的那样:维护不友好(检查哪个表单已关闭的状态)
于 2013-03-08T19:09:04.933 回答