Delegate with generic list signature for passing data to another form

162 Views Asked by At

I'm quite new in C#, so I'm struggling with this more than two days. I hope that some one can help me out with this one.

Below some simplified code from my application.

I want to pass a List from Form1 to Form2 using delegate and event.

How can I do this? I read tons of explanations about events and delegates, but I still can't figure it out, how this really works.

Form1:

public delegate List<string> ProfileImportEventHandler();
public event ProfileImportEventHandler ProfileImported;

private void btnImport_Click(object sender, EventArgs e)
{
 // raise an event
 OnProfileImported();
}
protected virtual void OnProfileImported()
{
   if (ProfileImported != null) // check if there are subscribers
   {
            ProfileImported();
   }
}

Form2:

public partial class Form2 : Form
{
    Form1 frm1;
    public Form1()
    {
      // Constructor logic
      frm1.ProfileChanged += new Form1.ProfileImportEventHandler(Form1_OnProfileImported);
    }
}

List<string> Form1_OnProfileImported()
{
    // TO DO
}

UPDATE

None of the solutions worked so far. Here is what I have already tried:

Form 2

    // use generic list for profiles that will be imported from USB-Stick
    private List<string> profilePaths = new List<string>();

    public delegate void ProfileImportEventHandler(object sender, ProfileImportEventArgs e);
    public event ProfileImportEventHandler ProfileImported;

    public delegate void ImportButtonClickedEventHandler();
    public event ImportButtonClickedEventHandler ButtonImportClicked;

    public delegate void HaveDataDelegate(IList<string> data);
    public event HaveDataDelegate HaveData;
//....

    private void btnImport_Click(object sender, EventArgs e)
    {
        // do something... 

        // raise an event
        var ea = new ProfileImportEventArgs(profilePaths);
        OnProfileImported(ea);

        OnButtonImportClicked();

        // When there is data:
        var copy = HaveData; // Use copy to avoid race conditions
        if (copy != null)
        {
            copy(profilePaths);
        }


      // close form
      this.Dispose();        
    }


    protected virtual void OnProfileImported(ProfileImportEventArgs ea)
    {
        if (ProfileImported != null) // check if there are any subscribers
        {
            ProfileImported(this, ea);
        }
    }
    protected virtual void OnButtonImportClicked()
    {
        if (ButtonImportClicked != null)
        {
            // fire event
            ButtonImportClicked();
        }
    }

Form 1

public partial class frm_1 : Form
{
// child form
frm_2 frm2;
public frm_1()
    {
        InitializeComponent();
        // do something...

        // not sure if this is correct code and the correct place for it
        frm2 = new frm_2();
        frm2.ProfileImported += new frm_2.ProfileImportEventHandler(frm2_OnProfileImported);
        //frm2.ProfileImported += frm2_OnProfileImported;

        frm2.ButtonImportClicked += new frm_2.ImportButtonClickedEventHandler(frm2_ButtonImportClicked);
        // In creation/init:
        frm2.HaveData += DataFromForm2;
    }
   void frm2_OnProfileImported(object sender, ProfileImportEventArgs e)
    {
        // do something            

    }

    void frm2_ButtonImportClicked()
    {
        // do something             
    }

    private void DataFromForm2(IList<string> data)
    {
        // Process the data from Form2.            
    }


}

What am I still missing? Thank you for your help.

3

There are 3 best solutions below

6
On
frm1.ProfileChanged += new Form1.ProfileImportEventHandler(Form1_OnProfileImported);

[…]

List<string> frmLoadProfileUSB_OnProfileImported()

First those names do not match. Second, with matching signatures you do not need (since C#2 if I recall correctly) to explicitly create the delegate. Thus:

frm1.ProfileChanged += frmLoadProfileUSB_OnProfileImported;

However, I think you have the event in the wrong place. It appears it is Form2 trying to pass data to Form1. Thus the event needs to be on Form2, with a delegate that is passed the data. Thus:

In Form2

public delegate void HaveDataDelegate(IList<string> data);
public event HaveDataDelegate HaveData;

// When there is data:
var copy = HaveData; // Use copy to avoid race conditions
if (copy != null) {
  copy(data);
}

In Form1

// In creation/init:
Form2Instance.HaveData += DataFromForm2;


private void DataFromForm2(IList<string> data) {
  // Process the data from Form2.
}
0
On

It's better not to use strong coupling. So best solution here would be to store data in database or create proxy-object (class/struct).

like: public (static) class ProfileChangesMonitor { ...your logic here }

2
On

If you want to use event handlers, you should follow the general pattern, defining a class that inherits EventArgs (supposing you want to involve a list in the event) in this way:

// Event Args
public class ProfileImportEventArgs : EventArgs {
    private IList<string> list;
    public ProfileImportEventArgs(IList<string> list) {
        this.list = list;
    }
    public IList<string> List {
        get {
            return this.list;
        }
   }
}

// Event Handler Delegate
public delegate void ProfileImportEventHandler(object sender, ProfileImportEventArgs e);


// Form1:
public event ProfileImportEventHandler ProfileImported;
// ...    
private void btnImport_Click(object sender, EventArgs e)
{
    // raise an event
    List<string> list = new List();
    // Add something to list if needed
    var ea = new ProfileImportEventArgs(list);
    OnProfileImported(ea);
    // Use ea.list here if necessary
}
protected virtual void OnProfileImported(ProfileImportEventArgs ea)
{
   if (ProfileImported != null) { // check if there are subscribers
        ProfileImported(this, ea);
   }
}

// Form2:

public partial class Form2 : Form
{
    Form1 frm1;
    public Form1()
    {
      // Constructor logic
      // TODO: Instantiate frm1 first.
      frm1.ProfileImported += new Form1.ProfileImportEventHandler(Form1_OnProfileImported);
    }
}

private void frmLoadProfileUSB_OnProfileImported(object sender, ProfileImportEventArgs e)
{
    // Use and/or modify e.List if needed         
}