关闭所有子表单时退出应用程序

时间:2015-09-21 13:29:00

标签: c# forms winforms parent-child exit

在我的winform应用程序中,我有一个表单在for循环期间创建其他表单。这个父表单仍然隐藏在那里纯粹是为了处理。

我将处理代码从程序类移开了,因为Application.Run似乎没有好好放在一个循环中,因为有多个实例会打开。

当儿童表格完成后,他们会被关闭。我想知道的是,即使父表单仍处于打开状态,我是否可以在这些表单关闭时退出应用程序。我尝试在父表单上公开List<bool>来存储哪些表单已关闭,但由于父表单没有实例名称,子表单无法访问列表 - 它由Application.Run(new FormProcessor(args));调用

更一般地说我想我是否有办法从子表单访问父表单的属性。

5 个答案:

答案 0 :(得分:3)

在每个子表单的构造函数中注入对父表单的引用,从而允许访问它。

或者,当创建每个子表单时,在父表单中添加对列表的引用,然后运行后台任务以等待所有子表单关闭。您可以通过订阅每个子表单上的表单已关闭事件并等待这些事件触发

来完成此操作

答案 1 :(得分:1)

我试图在评论中展示的一个简单例子如下。

您创建了一个额外的类来处理FormClosed事件的注册,例如:

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows.Forms;

namespace wfAutoClose {
  public class FormSubscriber : INotifyPropertyChanged, IDisposable {
    public event PropertyChangedEventHandler PropertyChanged;

    private readonly IList<Form> _forms = new ObservableCollection<Form>();
    public IList<Form> Forms {
      get {
        return _forms;
      }
    }

    public int FormCount {
      get {
        return _forms.Count;
      }
    }

    private void RaisePropertyChanged(string propertyName) {
      var localEvent = PropertyChanged;
      if (localEvent != null) {
        localEvent.Invoke( this, new PropertyChangedEventArgs( propertyName: propertyName ) );
      }
    }

    private void OnChildFormClosed(object sender, FormClosedEventArgs e) {
      Forms.Remove( sender as Form );
    }

    private void SubscribeToFormClosedEvent(Form childForm) {
      childForm.FormClosed += OnChildFormClosed;
    }

    private void UnsubscribeFromFormClosedEvent(Form childForm) {
      childForm.FormClosed -= OnChildFormClosed;
    }

    private void OnChildFormCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) {
      if (e.OldItems != null) {
        foreach (var item in e.OldItems) {
          UnsubscribeFromFormClosedEvent( item as Form );
        }
      }
      if (e.NewItems != null) {
        foreach (var item in e.NewItems) {
          SubscribeToFormClosedEvent( item as Form );
        }
      }
      RaisePropertyChanged( "FormCount" );
    }

    public void Dispose() {
      ( Forms as INotifyCollectionChanged ).CollectionChanged -= OnChildFormCollectionChanged;
    }

    public FormSubscriber() {
      ( Forms as INotifyCollectionChanged ).CollectionChanged += OnChildFormCollectionChanged;
    }
  }
}

然后可以在父表单中使用,然后只需在循环中添加表单,您的父表单就可以将自己注册到FormSubscriber的INotifyPropertyChanged事件。当没有更多可用表单时,它会显示FormCount == 0这是您将从应用程序退出的位置(通过调用Application.Exit()this.Close()

using System;
using System.ComponentModel;
using System.Windows.Forms;

namespace wfAutoClose {
  public partial class Form1: Form {
    FormSubscriber formSubscriber = new FormSubscriber();

    public Form1() {
      InitializeComponent();
      formSubscriber.PropertyChanged += OnPropertyChanged;
    }

    private void OnPropertyChanged( object sender, PropertyChangedEventArgs e ) {
      if (formSubscriber.FormCount == 0) {
        Application.Exit();
      }
    }

    private void Form1_Load( object sender, EventArgs e ) {
      for ( int i = 0; i < 3; i++ ) {
        Form form = new Form2() { Text = "Dynamic Form " + i };
        form.Show();
        formSubscriber.Forms.Add( form );
      }
    }

    private void Form1_FormClosed( object sender, FormClosedEventArgs e ) {
      formSubscriber.Dispose();
    }
  }
}

当然,在我的示例中,它们只是基本窗口,我不关心任何线程或其他GUI细节,但它应该向您展示您可以对事件注册和{的使用做些什么的基础知识{1}}(参见FormSubscriber)

答案 2 :(得分:1)

最简单的方法是将打开/关闭表单的信息保存在其他全局类中:

public static class Helper
{
   public static List<int> ChildFormsOpened { get; private set; }

   static Helper()
   {
       ChildFormsOpened = new List<int>();   
   }
}

您可以在打开时简单地添加表单哈希码。您可以在ctor中执行此操作或在子窗体打开时加载事件处理程序:

Helper.ChildFormsOpened.Add(this.GetHashCode());

因此,在代码中的某个时刻,您可以删除从集合中关闭的表单,并检查是否所有其他表单都已关闭。如果是,那么您可以通过调用Application.Exit()方法关闭您的应用程序:

    private void Form1_FormClosing(object sender, FormClosingEventArgs e)
    {
       Helper.ChildFormsOpened.Remove(this.GetHashCode());
       if(Helper.ChildFormsOpened.Count < 1) Application.Exit();
    }    

答案 3 :(得分:1)

使用ApplicationContext并订阅所有子表单的FormClosed()事件。在适当的时候检查Application.OpenForms集合和Exit()......

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

}

public class MyContext : ApplicationContext
{

    public MyContext()
    {
        // Open your Forms...
        for(int i = 1; i <= 5; i++)
        {
            Form frm = new Form();
            frm.Text = "Form #" + i.ToString();
            frm.FormClosed += Frm_FormClosed;
            frm.Show(); 
        }
    }

    private void Frm_FormClosed(object sender, FormClosedEventArgs e)
    {
        if (Application.OpenForms.Count == 0)
        {
            Application.Exit();
        }
    }

}

答案 4 :(得分:0)

感谢所有为此提供帮助的人。我想出了一个适合我的答案。我在窗体后面添加了一个事件处理程序。 origList变量存储formList的原始数据,否则foreach将继续执行可能已删除的列表的下一个条目。

for ( int i =0; i < formList.Count; i++)
        {
                string formName = formList[i];

                    Form1 frm = (new Form1(formName...);
                    frm.Show();
                    string contextName= formName;
                    frm.FormClosed += new FormClosedEventHandler((sender, e) => FrmClosed_Event(sender, e, contextName));                                     
        }

       public void FrmClosed_Event(object sender, FormClosedEventArgs e, string name)
        {
            foreach(string thisForm in origList)
            {
                if (thisForm == name)
                { formList.Remove(thisForm); }
            }
            if (formList.Count == 0)
            { Application.Exit(); }
        }