使用 Assembly.Load 创建外部项目的新 WinForm
create new WinForm of an external project with Assembly.Load
我在 C# 中有 2 个 windowsForm 项目(项目 A 和 B),但我想在项目 B 中通过代码添加对项目 A 的引用,并从项目 B 中调用项目 A。
我使用了 Assembly.Load 并且只有在删除 Main void 参数时它才有效。
项目A的窗体应该作为项目B的MdiParent打开。
我尝试使用 Assembly.load 和 activator.createinstance,但是当我尝试传递方法参数时它不起作用。
With param args is returning an error
(System.MissingMethodException: 'Constructor in type'
CompareXMLTools.Main 'not found.')
#using System.Reflection.Assembly
项目 A
Program.cs
namespace CompareXMLTools
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Main(args));
}
}
}
WindowsForm
namespace CompareXMLTools
{
public partial class Main : Form
{
public Main(string[] args)
{
InitializeComponent();
ArgsPassed = args;
}
}
}
项目 B
namespace XMLValidator
{
public partial class frmMain : Form
{
public frmMain(string[] args)
{
InitializeComponent();
ArgsPassed = args;
}
}
private void tsbrnCompareXML_Click(object sender, EventArgs e)
{
object dllUserControl = null;
System.Reflection.Assembly assembly2 = AppDomain.CurrentDomain.Load(File.ReadAllBytes(@"D:\Projetos C#\XMLValidator\XMLValidator\CompareXMLTools.exe"));
dllUserControl = assembly2.CreateInstance("CompareXMLTools.Main", true, System.Reflection.BindingFlags.Default, null, new string[] { }, System.Globalization.CultureInfo.CurrentCulture, null);
((frmMain)dllUserControl).MdiParent = this;
((frmMain)dllUserControl).Show();
}
}
注意:仅当我从 Main 方法中删除 ** string [] args
** 字段时,项目 B 命令才有效。
调用项目A新建的WinForm需要传参,请问怎么办?
我建议向 Form1 添加一个无参数的构造函数,这样您就可以从可能不知道它期望的参数数量(如果有的话)的外部程序集调用它,并添加处理 null
参数。
namespace XMLValidator
{
public partial class Main : Form
{
public Main() : this(null) { }
public Main(string[] args) {
InitializeComponent();
[Something] = args;
}
}
}
在此之后,如果您不想/不能使用接口(对这些程序集之间的契约有一个共同的 理解),您必须依靠您的Name
.
要加载和调用哪些表单的知识
可以使用 Activator.CreateInstance 重载传递参数,它接受一个类型(你知道你想要加载什么类型,一个表单)和 params object[]
.[=30 形式的参数=]
public static object CreateInstance (Type type, params object[] args);
params
中的每个对象代表您指定的 class 的构造函数所期望的参数。
无参数构造函数不需要任何参数,因此您在 args[0]
.
中传递 null
否则,args[0]
包含要调用的非空构造函数的参数,以初始化指定的 class。
object[] args = new object[1] { new string[] { "Args String", "Args Value", "Other args" } };
并致电:
Activator.CreateInstance([Type], args) as [Type];
我建议构建一个处理外部程序集初始化的中间体 class,自动提取一些有用的信息(NameSpace
,特定类型的资源 - Forms
,项目资源等)。所以你只需要提供一个表单的名称来激活和显示它。
例如,从您的 MDIParent 表单中的菜单:
public partial class MDIParent : Form
{
private ResourceBag formResources = null;
public MDIParent()
{
InitializeComponent();
formResources = new ResourceBag([Assembly Path]);
}
// [...]
// From a ToolStrip MenuItem, load with arguments
private void loadExternalFormToolStripMenuItem_Click(object sender, EventArgs e)
{
object[] args = new object[1] { new string[] { "Args String", "Args Value", "Other args" } };
Form form1 = formResources.LoadForm("Form1", args);
form1.MdiParent = this;
form1.Show();
}
// From another ToolStrip MenuItem, load using the default Constructor
private void loadExternalFormNoParamsToolStripMenuItem_Click(object sender, EventArgs e)
{
Form form1 = formResources.LoadForm("Form1");
form1.MdiParent = this;
form1.Show();
}
}
ResourceBag
帮手class:
也许可以向 public Form LoadForm()
添加重载以传递不同的 NameSpace
,以防您要加载不属于默认 NameSpace
的 class 对象].
using System.IO;
using System.Reflection;
using System.Windows.Forms;
internal class ResourceBag
{
private string m_AssemblyName = string.Empty;
private static Assembly asm = null;
public ResourceBag() : this(null) { }
public ResourceBag(string assemblyPath)
{
if (!string.IsNullOrEmpty(assemblyPath)) {
this.AssemblyName = assemblyPath;
}
}
public string NameSpace { get; set; }
public string AssemblyName {
get => m_AssemblyName;
set {
if (File.Exists(value)) {
m_AssemblyName = value;
asm = Assembly.LoadFrom(m_AssemblyName);
this.NameSpace= asm.GetName().Name;
}
else {
throw new ArgumentException("Invalid Assembly path");
}
}
}
public Form LoadForm(string formName, params object[] args)
{
if (asm == null) throw new BadImageFormatException("Resource Library not loaded");
return Activator.CreateInstance(asm.GetType($"{NameSpace}.{formName}"), args) as Form;
}
}
我在 C# 中有 2 个 windowsForm 项目(项目 A 和 B),但我想在项目 B 中通过代码添加对项目 A 的引用,并从项目 B 中调用项目 A。 我使用了 Assembly.Load 并且只有在删除 Main void 参数时它才有效。
项目A的窗体应该作为项目B的MdiParent打开。
我尝试使用 Assembly.load 和 activator.createinstance,但是当我尝试传递方法参数时它不起作用。
With param args is returning an error (System.MissingMethodException: 'Constructor in type' CompareXMLTools.Main 'not found.')
#using System.Reflection.Assembly
项目 A Program.cs
namespace CompareXMLTools
{
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Main(args));
}
}
}
WindowsForm
namespace CompareXMLTools
{
public partial class Main : Form
{
public Main(string[] args)
{
InitializeComponent();
ArgsPassed = args;
}
}
}
项目 B
namespace XMLValidator
{
public partial class frmMain : Form
{
public frmMain(string[] args)
{
InitializeComponent();
ArgsPassed = args;
}
}
private void tsbrnCompareXML_Click(object sender, EventArgs e)
{
object dllUserControl = null;
System.Reflection.Assembly assembly2 = AppDomain.CurrentDomain.Load(File.ReadAllBytes(@"D:\Projetos C#\XMLValidator\XMLValidator\CompareXMLTools.exe"));
dllUserControl = assembly2.CreateInstance("CompareXMLTools.Main", true, System.Reflection.BindingFlags.Default, null, new string[] { }, System.Globalization.CultureInfo.CurrentCulture, null);
((frmMain)dllUserControl).MdiParent = this;
((frmMain)dllUserControl).Show();
}
}
注意:仅当我从 Main 方法中删除 ** string [] args
** 字段时,项目 B 命令才有效。
调用项目A新建的WinForm需要传参,请问怎么办?
我建议向 Form1 添加一个无参数的构造函数,这样您就可以从可能不知道它期望的参数数量(如果有的话)的外部程序集调用它,并添加处理 null
参数。
namespace XMLValidator
{
public partial class Main : Form
{
public Main() : this(null) { }
public Main(string[] args) {
InitializeComponent();
[Something] = args;
}
}
}
在此之后,如果您不想/不能使用接口(对这些程序集之间的契约有一个共同的 理解),您必须依靠您的Name
.
可以使用 Activator.CreateInstance 重载传递参数,它接受一个类型(你知道你想要加载什么类型,一个表单)和 params object[]
.[=30 形式的参数=]
public static object CreateInstance (Type type, params object[] args);
params
中的每个对象代表您指定的 class 的构造函数所期望的参数。
无参数构造函数不需要任何参数,因此您在 args[0]
.
中传递 null
否则,args[0]
包含要调用的非空构造函数的参数,以初始化指定的 class。
object[] args = new object[1] { new string[] { "Args String", "Args Value", "Other args" } };
并致电:
Activator.CreateInstance([Type], args) as [Type];
我建议构建一个处理外部程序集初始化的中间体 class,自动提取一些有用的信息(NameSpace
,特定类型的资源 - Forms
,项目资源等)。所以你只需要提供一个表单的名称来激活和显示它。
例如,从您的 MDIParent 表单中的菜单:
public partial class MDIParent : Form
{
private ResourceBag formResources = null;
public MDIParent()
{
InitializeComponent();
formResources = new ResourceBag([Assembly Path]);
}
// [...]
// From a ToolStrip MenuItem, load with arguments
private void loadExternalFormToolStripMenuItem_Click(object sender, EventArgs e)
{
object[] args = new object[1] { new string[] { "Args String", "Args Value", "Other args" } };
Form form1 = formResources.LoadForm("Form1", args);
form1.MdiParent = this;
form1.Show();
}
// From another ToolStrip MenuItem, load using the default Constructor
private void loadExternalFormNoParamsToolStripMenuItem_Click(object sender, EventArgs e)
{
Form form1 = formResources.LoadForm("Form1");
form1.MdiParent = this;
form1.Show();
}
}
ResourceBag
帮手class:
也许可以向 public Form LoadForm()
添加重载以传递不同的 NameSpace
,以防您要加载不属于默认 NameSpace
的 class 对象].
using System.IO;
using System.Reflection;
using System.Windows.Forms;
internal class ResourceBag
{
private string m_AssemblyName = string.Empty;
private static Assembly asm = null;
public ResourceBag() : this(null) { }
public ResourceBag(string assemblyPath)
{
if (!string.IsNullOrEmpty(assemblyPath)) {
this.AssemblyName = assemblyPath;
}
}
public string NameSpace { get; set; }
public string AssemblyName {
get => m_AssemblyName;
set {
if (File.Exists(value)) {
m_AssemblyName = value;
asm = Assembly.LoadFrom(m_AssemblyName);
this.NameSpace= asm.GetName().Name;
}
else {
throw new ArgumentException("Invalid Assembly path");
}
}
}
public Form LoadForm(string formName, params object[] args)
{
if (asm == null) throw new BadImageFormatException("Resource Library not loaded");
return Activator.CreateInstance(asm.GetType($"{NameSpace}.{formName}"), args) as Form;
}
}