Frage

I've searched everywhere on this and can't find anyone doing anything similar. I'm quite a newbie at C# having worked 15 years with a non-object orientated language, so I hope I'm not missing something simple.

I am trying to make a standard Winform which get's inherited, so that I don't need to repeat the code I use every time (one of the joys of .Net over what I've used for years is the ability to centralize things far more).

My problem comes that I want to implement the ability to either call the derived classes as 'single instance' or 'multiple instance' when launched from the MDI and after much much searching I've almost achieved this using 'generics'. But I've got stuck with how to know which class the current form is, to pass that to the generic class to close the form.

A simplified version of my code will help understand my problem. This is my generic class designed for launching and closing the form. It determines if the Instance for T already exists, depending on if you are launching a single or multiple instance it either shows that, or creates a new instance of the form. The MDI for is passed in the launch methods to allow me to attach the new form to that.

public class FormLaunch<T> where T : MyBaseForm, new()
{
    public static T Instance;
    public static void LaunchultipleInstnace(FRMMDI mdi)
    {
        Instance = new T();
        Instance.MdiParent = mdi;
        Instance.Show();
        Instance.BringToFront();
    }
    public static void LaunchSingleInstance(FRMMDI mdi)
    {
        if (Instance == null) Instance = new T();
        Instance.MdiParent = mdi;
        Instance.Show();
        Instance.BringToFront();
    }
    public static void CloseInstance()
    {
        Instance = null;
    }
}

A 'Single Instance' version of the form is launched from the MDI using the following statement.

        FormLaunch<MyDerivedClass>.LaunchSingleInstance(this);

The problem comes that I would like to handle the closing of the form once in my base form and not have to do it every time in the derived forms. But I can't work out how to do this.

public partial class MyBaseForm : Form
{
    public MyBaseForm()
    {
        InitializeComponent();
    }
    private void MyBaseForm_FormClosed(object sender, FormClosedEventArgs e)
    {
        FormLaunch<this.GetType()>.CloseInstance();
    }
}

But this.GetType() does not work. If I was just using this form directly rather than inheriting it I could just use

        FormLaunch<MyBaseForm>.CloseInstance();

Or if I handled the FormClosed event in every derived class then I could just use

        FormLaunch<MyDerivedClass>.CloseInstance();

But I really want to do this in a way that stops me forgetting to do this every time in the derived class... because I wrote this a few months ago and have already forgotten pretty much every time I've used it.

EDIT: My question is really, what do I pass in the place of T in

        FormLaunch<T>.CloseInstance()

This needs to refer to the derived class and I can't seem to find that. this.GetType() refers to the correct glass but does not work.

War es hilfreich?

Lösung 2

You can simply subscribe to FormClosed in LaunchSingleInstance() and remove handling of close event from form itself completely:

public static void LaunchSingleInstance(FRMMDI mdi)
{
    if (Instance == null)
    {
        Instance = new T();
        Instance.FormClosed += (s, e) => CloseInstance();
    }
    Instance.MdiParent = mdi;
    Instance.Show();
    Instance.BringToFront();
}

A more direct answer - it is possible using reflection:

typeof(FormLaunch<>).MakeGenericType(this.GetType())
                    .GetMethod("CloseInstance")
                    .Invoke(null, null);

Andere Tipps

If what you want is just to enuse the single instance of the Form is opened you can read the answer of Jon Skeet to this question

And just a pair of another points.

  • You mix different things: .NET generics and inheritance.
    • this.GetType() returns an instance of System.Type class, describing the current instance class (this),
    • Type parameter in GenericClass<TypeParameter> is just a name of the concrete class in using, or a type parameter name in the generic class definition: Generic<TParam>
  • you can't define generic Control or Form classes. The Designer is not capable to serialize them.
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top