在构造函数中传递 C# 函数以用作 EventHandler 委托的订阅者

问题描述 投票:0回答:1

我花了一些时间学习 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);
         }
     }
 }
c# winforms .net-core delegates eventhandler
1个回答
0
投票

操作委托经常用于在类似场景中生成通知。您已经有一个 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);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.