如何使用此通用方法将参数传递给表单?

时间:2018-05-23 19:52:02

标签: c# winforms .net-4.0

我有这种通用方法在面板中打开表单,此方法继承自Form,目前限制它有一个空构造函数(where T : Form, new())

public void OpenForms<T>() where T : Form, new()
{
    Form form = container_panel.Controls.OfType<T>().FirstOrDefault();
    if (form !=null)
    {
        //If the instance is minimized we leave it in its normal state
        if (form.WindowState == FormWindowState.Minimized)
        {
            form.WindowState = FormWindowState.Normal;
        }
        //If the instance exists, I put it in the foreground
        form.BringToFront();
        return;
    }
    //The form opens
    form = new T();
    form.TopLevel = false;
    container_panel.Controls.Add(form);
    container_panel.Tag = form;
    form.Show();
}

以这种方式来称呼它:

OpenForms<Form1>();

如何调整此函数以将参数传递给表单?

在这种情况下,我需要将两个参数传递给表单,如下所示:

OpenForms<Form1>(param1, param2);
  

并非所有表单都接收参数,但将来您可能需要使用1/2/3参数,具体取决于表单。

     

参数的类型可能有所不同:boolstringint ......

这可以收到这样的东西:

public void OpenForms<T>(params object[] args) where T : Form, new() { ... }

我们的想法是能够以下列方式使用它:

object[] args = new object[] { "a", true };

OpenForms<Form1>(args);
OpenForms<Form1>("a", 2, false);
OpenForms<Form1>();

收到参数后,您可以在创建表单时使用它们。

知道如何实现这个目标吗?

修改

我想这两个表格的例子

public partial class Form1 : Form
{
    public Form1(string param1, bool param2)
    {
        InitializeComponent();
    }

    //......
}

public partial class Form2 : Form
{
    public Form2()
    {
        InitializeComponent();
    }

    //......
}

尝试按此方式拨打电话时:

OpenForms<Form1>("a" false); //Error
OpenForms<Form2>();

错误:

  

必须是具有公共无参数构造函数的非抽象类型,才能在泛型类型或方法'AbrirFormulario(params object [])'

中将其用作参数'T'

3 个答案:

答案 0 :(得分:4)

为此,您需要删除new()约束以允许没有无参数构造函数的表单:

public void OpenForms<T>(params object[] args) where T : Form

现在,为了创建实例,您需要使用Activator.CreateInstance

T form = default(T);

if (args == null || args.Length == 0)
    form = Activator.CreateInstance<T>();
else
    form = (T)Activator.CreateInstance(typeof(T), args);

编辑:完整解决方案

public void OpenForms<T>(params object[] args) where T : Form
{
    Form form = container_panel.Controls.OfType<T>().FirstOrDefault();
    if (form !=null)
    {
        //If the instance is minimized we leave it in its normal state
        if (form.WindowState == FormWindowState.Minimized)
        {
            form.WindowState = FormWindowState.Normal;
        }
        //If the instance exists, I put it in the foreground
        form.BringToFront();
        return;
    }
    if (args == null || args.Length == 0)
        form = Activator.CreateInstance<T>();
    else
        form = (T)Activator.CreateInstance(typeof(T), args);
    form.TopLevel = false;
    container_panel.Controls.Add(form);
    container_panel.Tag = form;
    form.Show();
}

答案 1 :(得分:1)

这是一种替代方法,它不需要Form来实现接口或真正关心它是如何构造的。

假设我们有一个Form,仅用于测试目的:

public class Form3 : Form
{
    public Form3(bool someParameter, string someTitle)
    {

    }
}

现在有一些关于构造函数的有用的自我记录功能,即参数具有名称。使用这样的东西:

public void OpenForms<T>(params object[] args) where T : Form
{
    //...
}

不向调用者提供有关“参数”是什么,它们属于什么顺序或它们的含义的任何信息。所以当你这样称呼它时:

OpenForms<Form3>(true, "Some Value");

Intellisense对你没有帮助,因为它只是表明你需要将一些(或没有)参数传递给方法。相反,更好的方法是使用工厂Func<T>来构建表单:

public void OpenForms<T>(Func<T> factoryMethod) where T : Form
{
    Form form = container_panel.Controls.OfType<T>().FirstOrDefault();
    if (form != null)
    {
        //If the instance is minimized we leave it in its normal state
        if (form.WindowState == FormWindowState.Minimized)
        {
            form.WindowState = FormWindowState.Normal;
        }
        //If the instance exists, I put it in the foreground
        form.BringToFront();
        return;
    }
    form = factoryMethod();
    form.TopLevel = false;
    container_panel.Controls.Add(form);
    container_panel.Tag = form;
    form.Show();
}

然后这样调用(请注意你如何也可以省略OpenForms调用的<Form3>部分,推断它!):

OpenForms(() => new Form3(true, "Title"));

随着所有有用的intellisense伴随着它:

enter image description here

所以现在你有了自我编写代码,无论表单是如何构造的,并且你没有强制一个没有关于哪些参数属于哪里的真实文档(在代码中)的接口。

答案 2 :(得分:0)

另一种解决方案是创建Interface以创建允许接收参数的方法。

这是一个例子:

public interface IForms
{
    void InitializeParameters(params object[] args);
}

这里我们定义一个必须符合实现此接口的表单的方法InitializeParameters

稍后,在必须从通用表单调用的表单中,我们在其定义中添加接口,并使用必需的方法:

public partial class Form1 : Form, IForms
{
    public Form1()
    {
        InitializeComponent();
    }

    public void InitializeParameters(params object[] args)
    {
        if (args.Length==2)
        {
            string param1 = args[0].ToString();
            int param2 = (int)args[1];
        }
        else
        {
            throw new Exception("The number of parameters is incorrect");
        }

    }       
}

现在我们定义通用方法以按以下方式打开表单:

private void OpenForms<T>(params object[] args) where T : Form,IForms,  new()
{
    Form form;
    form= new T();
    ((IForms)form).InitializeParameters(args);
    form.Show();
}

最后,使用它的方法如下:

OpenForms<Form1>("a", 2);
OpenForms<Form2>("a", 2, "b");
OpenForms<Form3>();
  

必须考虑到,由于已定义了InitializeParameters方法,示例2和3 将为不正确数量的参数提供例外。使用此表格,必须控制每个案例。

感谢用户@Pikoh的帮助。

相关问题