C# 反射动态创建窗体添加组件

1、通过XML反射生成窗体,如果将反射的组件(非可视组件IComponet)添加到窗体中

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Reflection;

namespace ReflectionLoadFormDemo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            //手动添加控件
            TextBox textBox = new TextBox();
            textBox.Name = "txtTest";
            textBox.Location = new Point(20, 20);
            textBox.Text = "手动添加";
            this.Controls.Add(textBox);

            //通过反射操作来添加控件
            //System.Windows.Forms所在的dll文件路径
            Assembly assembly = Assembly.LoadFile(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.Windows.Forms.dll");
            Type type = assembly.GetType("System.Windows.Forms.TextBox");
            //调用实例化方法(非静态方法)需要创建类型的一个实例
            object instanceObject = Activator.CreateInstance(type);

            //Name属性
            PropertyInfo propertyInfoName = type.GetProperty("Name");
            propertyInfoName.SetValue(instanceObject, "txtTest");

            //Location属性
            PropertyInfo propertyInfoLocation = type.GetProperty("Location");
            propertyInfoLocation.SetValue(instanceObject, new Point(60, 60));

            //Text属性
            PropertyInfo propertyInfoText = type.GetProperty("Text");
            propertyInfoText.SetValue(instanceObject, "反射添加控件");

            if (instanceObject is TextBox)
            {
                this.Controls.Add((TextBox)instanceObject);
            }
        }
    }
}

运行示例:

在你的xml文件中,是否存在这样的节点

<TextBox>

<Name>txtTest</Name>

<Location><X>60</X><Y>50</Y></Location>

<Text>Hello</Text>

</TextBox>

 

读取xml节点,请参考博客【C#读取配置文件Ini,json,xml并绑定到树图上】 https://blog.csdn.net/ylq1045/article/details/108283457

                  instance = Activator.CreateInstance(type);
                    if (typeof(Form).IsAssignableFrom(type))
                    {
                        if (!isDesiger)
                        {
                            frm = (Form)Activator.CreateInstance(type);
                        }  
                        else
                            instance = host.CreateComponent(type, nameAttr.Value);
                    }
                    else
                    {
                        if (!isDesiger)
                        {
                            if (instance is Control)
                                frm.Controls.Add((Control)instance);
                            else
                            {
                                if (instance is Component)
                                {
                                    frm.Container.Add((IComponent)instance);
                                }
                            }
                        }
                        else
                            instance = host.CreateComponent(type, nameAttr.Value);
                    }

frm.Container 始终为null,该属性是只读属性

当前要插入的是 IComponent

组件 以System.IO.Ports.SerialPort 为例,不是一个控件 因此 不能使用 controls.add(...)

模仿如下代码:

/// <summary>
        /// 添加一个组件
        /// </summary>
        private IComponent AddComponent()
        {
            //组件所在的dll
            Assembly assembly = Assembly.LoadFile(@"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.6.1\System.dll");
            Type type = assembly.GetType("System.IO.Ports.SerialPort");
            object instanceObject = Activator.CreateInstance(type);

            //PortName属性
            PropertyInfo propertyInfoLocation = type.GetProperty("PortName");
            propertyInfoLocation.SetValue(instanceObject, "COM1");

            //Text属性
            PropertyInfo propertyInfoText = type.GetProperty("BaudRate");
            propertyInfoText.SetValue(instanceObject, 9600);

            return (IComponent)instanceObject;
        }

使用时 如下:

//只是一个字段 不能添加到窗体的控件中
            IComponent component = AddComponent();
            if (component is System.IO.Ports.SerialPort)
            {
                MessageBox.Show($"{((System.IO.Ports.SerialPort)component).BaudRate}");
            }

 

控件Control一定是一个组件,当某些组件可能不是控件。不是控件时,只能做为Form类的成员字段

 

bizdbobj1这个组件 就是窗体(类)的一个成员字段 field 。你看下 .designer.cs的代码就明白了

本质保存一个BizPageFrm类下面的字段bizdbobj1而已

bizdbobj1其实就是继承datatable,这个组件不一定会是bizpagefrm,只是这个时候恰好是他的一个属性字段

this.components = new System.ComponentModel.Container();
this.bizDbObj1 = new Nif.Controls.BizDbObj(this.components);

其实我就想把这种情况如何通过XML反射到当前窗体中