使用简单注入器 c# 时从父窗体设置子 winform 属性
set child winform properties from a parent form when using simple injector c#
我有一个 form1(不是 mdi),它在按钮单击事件时显示对话框,对话框基本上是一个弹出窗体,它在 datagridview 控件上显示数据。
我正在使用简单的注射器。
PopUpForm 有一个名为 LocationData 的 属性,它是一个数据表。我需要在 form1(父级)中设置 属性,以便数据在屏幕上显示时可以显示在 PopUpForm 上。
抱歉,我是简单注射器的新手,仍在学习中,如有任何帮助或指导,我们将不胜感激。我什至不知道我做的对不对。
form1
按钮点击事件
this._formOpener.ShowModalForm<PopUpForm>();
PopUpForm
public partial class PopUpForm : Form
{
public DataTable LocationData { get; set; }
public PopUpForm()
{
InitializeComponent();
}
private void PopUpForm_Load(object sender, EventArgs e)
{
dgvNearestLocations.DataSource = LocationData;
}
}
程序class
static class Program
{
private static Container container;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(container.GetInstance<Form1>());
}
private static void Bootstrap()
{
// Create the container as usual.
container = new Container();
// Register your types, for instance:
container.RegisterSingleton<IFormOpener, FormOpener>();
container.Register<Form1>(Lifestyle.Singleton); ;
container.Register<PopUpForm>(Lifestyle.Singleton); ;
// Optionally verify the container.
container.Verify();
}
}
FormOpener
public class FormOpener : IFormOpener
{
private readonly Container container;
private readonly Dictionary<Type, Form> openedForms;
public FormOpener(Container container)
{
this.container = container;
this.openedForms = new Dictionary<Type, Form>();
}
public DialogResult ShowModalForm<TForm>() where TForm : Form
{
using (var form = this.GetForm<TForm>())
{
return form.ShowDialog();
}
}
private Form GetForm<TForm>() where TForm : Form
{
return this.container.GetInstance<TForm>();
}
}
首先,您可能从 复制了 FormOpener。但是您错过了有关 Forms 需要瞬态的部分。不要将您的表单注册为 Singleton
。特别是因为你处理了它们,这将只工作一次。下次您想显示 Form
时,您将得到 ObjectDisposedException
.
当您将表单注册为 Transient
时,Simple Injector 会告诉您表单实现了 IDisposable
,这(当然)是正确的。但是因为你在 FormOpener
中小心处理,你可以安全地抑制这个警告。像这样注册您的表格:
private static void RegisterWindowsForms(
this Container container, IEnumerable<Assembly> assemblies)
{
var formTypes =
from assembly in assemblies
from type in assembly.GetTypes()
where type.IsSubclassOf(typeof(Form))
where !type.IsAbstract
select type;
foreach (var type in formTypes)
{
var registration = Lifestyle.Transient.CreateRegistration(type, container);
registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent,
"Forms are disposed by application code. Letting Simple Injector do this " +
"is problematic because that would need a scope, which is impossible to do.");
container.AddRegistration(type, registration);
}
}
回答你的问题:
您需要的是一些额外的基础设施来初始化 Form
.
通过让您的表单实现一个接口IFormInit<T>
,您可以将数据传递给表单并直接显示它。
public interface IFormInit<T> : IDisposable
{
DialogResult InitAndShowForm(T data);
}
为了让 Simple Injector 基于这个接口创建表单,我们需要在容器中注册它们。我们可以让 Simple Injector 通过提供程序集列表来搜索所有已关闭的实现,如下所示:
container.Register(typeof(IFormInit<>), assemblies, Lifestyle.Transient);
请注意,Simple Injector 会自动将这些注册与来自 RegisterWindowsForms
的注册合并。所以你现在可以通过调用获得 Form
的实例:
container.GetInstance<PopupForm>();
or
container.GetInstance<IFormInit<SomeDataClass>>();
您现在可以将此代码添加到您的 FormOpener
class:
public DialogResult ShowModalForm<TData>(TData data)
{
Type formType = typeof(IFormInit<>).MakeGenericType(typeof(TData));
dynamic initForm = this.container.GetInstance(formType);
DialogResult result = (DialogResult) initForm.InitAndShowForm(data);
initForm.Dispose();
return result;
}
这将根据它实现的 IFormInit<T>
类型从容器中获取 Form
。获取表单时调用界面上的函数,而不是直接调用Form.ShowDialog()
。当表单关闭时,您将处理该表单。
注意:dynamic
键入的使用可能需要说明。为什么需要它是受 here.
描述的 QueryHandler
模式的启发
用法如下:
// Add a specific class to pass to the form
public class LocationDataWrapper
{
public DataTable LocationData { get; set; }
}
public partial class PopUpForm : Form, IFormInit<LocationDataWrapper>
{
public PopUpForm() => InitializeComponent();
// Implement the interface, the loaded event can be removed
public DialogResult InitAndShowForm(LocationDataWrapper data)
{
dgvNearestLocations.DataSource = data.LocationData;
return this.ShowDialog();
}
}
按钮点击事件
DialogResult result = this._formOpener.ShowModalForm(new LocationDataWrapper
{
LocationData = locationDataTable,
});
您可以为每个表单创建包装器或数据 classes,当您让此 Form
实现 IFormInit<ThisSpecificDataClass>
.
时,它会自动显示正确的表单
我有一个 form1(不是 mdi),它在按钮单击事件时显示对话框,对话框基本上是一个弹出窗体,它在 datagridview 控件上显示数据。
我正在使用简单的注射器。
PopUpForm 有一个名为 LocationData 的 属性,它是一个数据表。我需要在 form1(父级)中设置 属性,以便数据在屏幕上显示时可以显示在 PopUpForm 上。
抱歉,我是简单注射器的新手,仍在学习中,如有任何帮助或指导,我们将不胜感激。我什至不知道我做的对不对。
form1
按钮点击事件
this._formOpener.ShowModalForm<PopUpForm>();
PopUpForm
public partial class PopUpForm : Form
{
public DataTable LocationData { get; set; }
public PopUpForm()
{
InitializeComponent();
}
private void PopUpForm_Load(object sender, EventArgs e)
{
dgvNearestLocations.DataSource = LocationData;
}
}
程序class
static class Program
{
private static Container container;
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(container.GetInstance<Form1>());
}
private static void Bootstrap()
{
// Create the container as usual.
container = new Container();
// Register your types, for instance:
container.RegisterSingleton<IFormOpener, FormOpener>();
container.Register<Form1>(Lifestyle.Singleton); ;
container.Register<PopUpForm>(Lifestyle.Singleton); ;
// Optionally verify the container.
container.Verify();
}
}
FormOpener
public class FormOpener : IFormOpener
{
private readonly Container container;
private readonly Dictionary<Type, Form> openedForms;
public FormOpener(Container container)
{
this.container = container;
this.openedForms = new Dictionary<Type, Form>();
}
public DialogResult ShowModalForm<TForm>() where TForm : Form
{
using (var form = this.GetForm<TForm>())
{
return form.ShowDialog();
}
}
private Form GetForm<TForm>() where TForm : Form
{
return this.container.GetInstance<TForm>();
}
}
首先,您可能从 Singleton
。特别是因为你处理了它们,这将只工作一次。下次您想显示 Form
时,您将得到 ObjectDisposedException
.
当您将表单注册为 Transient
时,Simple Injector 会告诉您表单实现了 IDisposable
,这(当然)是正确的。但是因为你在 FormOpener
中小心处理,你可以安全地抑制这个警告。像这样注册您的表格:
private static void RegisterWindowsForms(
this Container container, IEnumerable<Assembly> assemblies)
{
var formTypes =
from assembly in assemblies
from type in assembly.GetTypes()
where type.IsSubclassOf(typeof(Form))
where !type.IsAbstract
select type;
foreach (var type in formTypes)
{
var registration = Lifestyle.Transient.CreateRegistration(type, container);
registration.SuppressDiagnosticWarning(DiagnosticType.DisposableTransientComponent,
"Forms are disposed by application code. Letting Simple Injector do this " +
"is problematic because that would need a scope, which is impossible to do.");
container.AddRegistration(type, registration);
}
}
回答你的问题:
您需要的是一些额外的基础设施来初始化 Form
.
通过让您的表单实现一个接口IFormInit<T>
,您可以将数据传递给表单并直接显示它。
public interface IFormInit<T> : IDisposable
{
DialogResult InitAndShowForm(T data);
}
为了让 Simple Injector 基于这个接口创建表单,我们需要在容器中注册它们。我们可以让 Simple Injector 通过提供程序集列表来搜索所有已关闭的实现,如下所示:
container.Register(typeof(IFormInit<>), assemblies, Lifestyle.Transient);
请注意,Simple Injector 会自动将这些注册与来自 RegisterWindowsForms
的注册合并。所以你现在可以通过调用获得 Form
的实例:
container.GetInstance<PopupForm>();
or
container.GetInstance<IFormInit<SomeDataClass>>();
您现在可以将此代码添加到您的 FormOpener
class:
public DialogResult ShowModalForm<TData>(TData data)
{
Type formType = typeof(IFormInit<>).MakeGenericType(typeof(TData));
dynamic initForm = this.container.GetInstance(formType);
DialogResult result = (DialogResult) initForm.InitAndShowForm(data);
initForm.Dispose();
return result;
}
这将根据它实现的 IFormInit<T>
类型从容器中获取 Form
。获取表单时调用界面上的函数,而不是直接调用Form.ShowDialog()
。当表单关闭时,您将处理该表单。
注意:dynamic
键入的使用可能需要说明。为什么需要它是受 here.
QueryHandler
模式的启发
用法如下:
// Add a specific class to pass to the form
public class LocationDataWrapper
{
public DataTable LocationData { get; set; }
}
public partial class PopUpForm : Form, IFormInit<LocationDataWrapper>
{
public PopUpForm() => InitializeComponent();
// Implement the interface, the loaded event can be removed
public DialogResult InitAndShowForm(LocationDataWrapper data)
{
dgvNearestLocations.DataSource = data.LocationData;
return this.ShowDialog();
}
}
按钮点击事件
DialogResult result = this._formOpener.ShowModalForm(new LocationDataWrapper
{
LocationData = locationDataTable,
});
您可以为每个表单创建包装器或数据 classes,当您让此 Form
实现 IFormInit<ThisSpecificDataClass>
.