我花了一些时间学习 C# 中的委托,并连接了一个包含两个表单的小型 Windows 表单应用程序来测试它们。
我的目标是让
AddContactForm
使用 ContactsForm
委托将新的联系人数据推送回 EventHandler
。我目前正在使用下面的代码,但最终我想将 ContactAddedHandler
设为 AddContactForm
私有,并将一个函数传递给 AddContactForm
构造函数,该函数用于像这样订阅委托:
public AddContactForm(SomeSubscriberFunction foo)
{
ContactAddedHandler += foo;
}
我尝试过对以下内容进行
SomeSubscriberFunction
的各种排列,但没有成功:
Func<object?, AddContactEventArgs?>
Func<AddContactEventArgs?>
Action<object?, AddContactEventArgs?>
如果有人可以就以下两个问题提供任何指导,我们将不胜感激:
#1。我是否以完全非最佳实践的方式处理这个问题,如果是的话,正确的方法是什么?
#2。如果这种使用委托的方法是正确的,我怎样才能实现我想要做的事情?
谢谢你。
联系表格
public void addContactBtn_Click(Object sender, EventArgs e)
{
AddContactForm addContactForm = new AddContactForm();
addContactForm.ContactAddedHandler += ContactAdded;
addContactForm.Show();
}
public void ContactAdded(object? sender, AddContactForm.AddContactEventArgs e)
{
Console.Write("Contact Added");
}
添加联系表格
public partial class AddContactForm : Form
{
public class AddContactEventArgs(Contact contact) : EventArgs
{
public Contact contact = contact;
}
public event EventHandler<AddContactEventArgs>? ContactAddedHandler;
public AddContactForm()
{
InitializeComponent();
}
private void saveContactBtn_Click(object sender, EventArgs e)
{
Contact c = new Contact("Test");
AddContactEventArgs args = new AddContactEventArgs(c);
if (ContactAddedHandler != null)
{
ContactAddedHandler(this, args);
}
}
}
操作委托经常用于在类似场景中生成通知。您已经有一个 Contact 类对象,它是存储所需信息的对象。
您很可能不需要自定义 EventArgs 对象来包装相同的数据。
例如,如果 Action 委托通知仅限于创建 Form 类的代码:
注意:为 .NET 6+ 编写,因为您有
windows-forms-core
标签
public partial class ContactForm : Form {
public ContactForm() => InitializeComponent();
private void AddContactBtn_Click(object sender, EventArgs e) {
Action<Contact> contactAdded = (contact) => Debug.WriteLine(contact.Name);
AddContactForm addContact = new(contactAdded);
addContact.ShowDialog();
}
}
如果 Action 委托只能通过表单的构造函数注入,如本文所示,您可以简单地将委托分配给私有字段并在需要时调用它:
public partial class AddContactForm : Form {
Action<Contact>? NotifyNewContact = null;
public AddContactForm() => InitializeComponent();
public AddContactForm(Action<Contact> newContact) : this() => NotifyNewContact = newContact;
private void SaveContactBtn_Click(object sender, EventArgs e) {
NotifyNewContact?.Invoke(new("Test"));
}
}
您还可以从外部访问该操作并添加多个订阅者。
您可以像以前一样使用多播委托。但最好创建一个间接级别,添加
event
关键字,以便在幕后创建 add()
和 remove()
方法,以保护对象。
您可以在构造函数中执行此操作:
public AddContactForm(Action<Contact> newContact) : this() => NotifyNewContact = newContact;
// Instead of NotifyNewContact += newContact
但不是这个:
addContact.NotifyNewContact = (c) => Debug.WriteLine(c.Name);
// Instead of += (c) => [...];
public partial class AddContactForm : Form {
protected internal event Action<Contact>? NotifyNewContact = null;
public AddContactForm() => InitializeComponent();
public AddContactForm(Action<Contact> newContact) : this() => NotifyNewContact += newContact;
private void SaveContactBtn_Click(object sender, EventArgs e) {
NotifyNewContact?.Invoke(new("Test"));
}
}
然后,您可以将多个委托(其中
AddContactForm
的实例可见)添加到可以传递 Action 委托的任何其他对象或以许多不同的其他方式:
public partial class ContactForm : Form {
// [...]
private void AddContactBtn_Click(object sender, EventArgs e) {
Action<Contact> contactAdded = (contact) => Debug.WriteLine(contact.Name);
AddContactForm addContact = new(contactAdded);
// Subscribe a second time, just a lambda
addContact.NotifyNewContact += (c) => Debug.WriteLine(c.Name);
// Subscribe using a delegate that something else provided
// Assume otherContact is coming from elsewhere
Action<Contact> otherContact = new((c)=> Debug.WriteLine(c.Name));
addContact.NotifyNewContact += otherContact;
// Subscribe using a method that matches the signature
addContact.NotifyNewContact += ProcessContact;
// [...]
}
// [...]
private void ProcessContact(Contact contact) {
Debug.WriteLine(contact.Name);
}
}