简体   繁体   中英

The concept of callbacks (C#)

Hi I have a form (Form A) which has a button "Add" which pops up a text-entering form (Form B). After you've entered the text in Form B, you press "OK" (btnOK). At this point I want Form A to get the text and do something with it.

From what I see I have two options:

1) Form A passes a function (delegate) to Form B which executes it in the btnOK_Click function.

2) I somehow register a method in Form A with the btnOK.Click event.

Am I on the correct track and can you think of any solutions to a similar problem that I can read because I get in trouble with static methods and events...

If Form B is a modal window, you could add a public string property to Form B.

When the user is closing Form B you could set the property to the text that was entered by the user. Then, back in Form A you could read the public property of Form B to get the text that the user entered.

Add a property to form B that is something like

public class FormB { ...
   public string Text
   {
      get { return textBox.Text; }
   }
   ...
}

If you show form b like follows:

FormB b = new FormB();
WPF: if (b.ShowDialog() != true) return;
Winforms: if (b.ShowDialog(this) != DialogResult.Ok) return;

string txt = b.Text;

So basically what is happening is you are showing the modal form b, where the user can enter text. Once the form is closed, b.ShowDialog will return from blocking. At that point, you can ask for b's Text property and retrieve the string. The Text property should be bound to b's textbox using some method.

If you don't want to show b modally, you can do this:

FormB b = new FormB();
b.Closed += new EventHandler(FormB_Closed);

b.Show();

private void FormB_Closed(object sender, EventArgs e)
{
    string text = ((FormB)sender).Text;

    ... do something
}

A better solution would be to put a public property on Form B containing the text you need. Then, just access that property from Form A after Form B has exited.

I prefer #1 - passing a delegate is clean and simple

class BInputValues {
    public String Field1 { get; set; }
    //...
};

partial class FormB {
    readonly Action<BInputValues> callback;

    public FormB(Action<BInputValues> callback) {
        this.callback = callback;
    }

    protected override void btnOK_Click(object sender, EventArgs e) {
        callback(new BInputValues {
            Field1 = Field1.Text, 
            //...
        });
    }
}

override void btnAdd_click() {
    var formb = new FormB(args => {
        // do something with args
    });
    formb.ShowModal();
}

You could also create a Subclass of Form...

public class FormWithResult : Form
{
    protected object FormResult { get; set; }

    public DialogResult ShowDialog(out object result)
    {
        DialogResult dr = ShowDialog();
        result = FormResult;
        return dr;
    }

    public DialogResult ShowDialog(out object result, IWin32Window win)
    {
        DialogResult dr = ShowDialog(win);
        result = FormResult;
        return dr;
    }

    public void Return(object result)
    {
        FormResult = result;
        Close();
    }

}

Then you can write this to Call a modal form and retrieve a result

        popup p = new popup();
        object result;
        p.ShowDialog(out result);
        MessageBox.Show((string)result);

And in your popup form you can either do:

        FormResult = textBox1.Text;
        Close();

OR

        Return(textBox1.Text);

To Close the form and return the value.

Subclassing Form has drawbacks as well of course, but I'll throw this out as another solution.

As a side not, a generic version of this where you could Strongly type the return value would be much better if it weren't for this limitation at design time: Visual Studio 2008 Winform designer fails to load Form which inherits from generic class

If you wanted Asynchronous results obviously this would have to be tweaked. I assume you are using Modal popups.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM