开发者

Opening a winform from a user control and passing back values to the usercontrol

I was wondering if it is possible to have a user 开发者_如何学Gocontrol open a winform that allows a user to select options on it and then when he closes the form - the options / values he selected are returned to the user control?


Why not create some public properies on your dialog form, and access them from the UserControl once the dialog has been closed?

public class OptionsForm : Form
{
    // ...

    public string Option1 { get; set; }
    public bool Option2 { get; set; }
}

And then, within the UserControl:

public void ShowOptionsForm()
{
    using (var form = new OptionsForm())
    {
        if (form.ShowDialog() == DialogResult.OK)
        {
            var option1Value = form.Option1;
            var option2Value = form.Option2;

            // use option values...
        }
    }
}


Please consider this answer as an "extended comment" on Steve Greatrex's now-accepted answer : it's too long for a comment, and I want to demonstrate a few options, add a few "flavours" to the taste. This is not at all a "criticism" of Steve's answer which, imho, hit the "bullseye."

Assumptions : if I had read the question earlier, I would have queried the OP via a comment on each of these points :

  1. the OP did not specify whether the Form to be "shown" was to be shown modally or not.

  2. the OP did not specify whether the Form was to be re-created each time it was shown, or whether one instance of it should be created and re-used.

  3. the OP wrote "open a winform that allows a user to select options on it ... snip ... "options / values he selected are returned" : Steve's code does not show exactly how the Properties exposed as Public are set, but I'm going to assume that the OP probably intended to mean that the user interacted with some Controls on the shown Form, and that the "options / values" he refers to are Properties of Controls on the Form : like the end-user typing some text in a TextBox, or the selected indexes in a ListBox with its SelectionMode set to allow one of two choices of multiple selection.

  4. the OP does not say if it's desireable that the Form (if used repeatedly) retain the results of the last interactions of the end-user with the Controls on the Form as described above.

  5. the OP says nothing about whether the Form shown by the UserControl has its Parent property set to some other valid container : I'll assume they meant the Form to be displayed "parent-less."

Comments :

  1. if the OP intended the Form to be shown modally : in order for Steve's code to work, the 'ControlBox of the Form would have to eliminated as an option, and a Button put on the Form whose 'DialogResult property was set to "OK," and whose 'Click Event closed the Form : without those conditiions being met the result of ShowDialog in Steve's code would never return "OK," and the properties' values would never be set. Note : closing a Form via the 'ControlBox will return a DialogResult of "Cancel."

  2. re-use of the shown Form : if we assume the Form will probably be re-used, then why not create it once and 'Show and 'Close as necessary ? Let's consider the possibility that there may be good reasons to expose the created Form as a Public member of the UserControl.

Consider the following alternative idea : trying to present a solution as "different" as possible from Steve's : just to demonstrate, explore, the options.

Our "shown Form" will have a TextBox and a ListBox that allows multiple selections : our goal is to expose the Text in the TextBox and the current selection of Indices in the ListBox.

  1. Form has a ControlBox : does not require a Button to close as described above.

  2. it doesn't matter if the Form is shown modally or not : will set properties the same way in either case.

  3. the Public properties to be set are to be based on reading the current state of Controls on the shown Form.

  4. the Form is created once and exposed as Public : because of this a "side-effect" is that when the Form is re-displayed it will retain the previous results of what the user selected, etc. Of course there are other ways you could easily control that in your code to make one or all of the Controls "virgin" again.

in The "shown Form" which we have named 'DataEntryForm :

Just as Steve shows we define public properties to expose ;

public string TextEntered { get; set; }

public ListBox.SelectedIndexCollection LBSelection { get; set; }

In the Form Closing Event we update the properties based on the state of the Controls :

private void DataEntryForm_FormClosing(object sender, FormClosingEventArgs e)
{
    TextEntered = textBox1.Text;
    LBSelection = listBox1.SelectedIndices;
}

in the UserControl we create a public property of type 'DataEntryform (reason why to be explained)

public DataEntryForm theDataEntryForm { get; set; }

We create an instance of the DataEntryForm in the Load Event of the UserControl and assign it to the public Property

private void UserControl1_Load(object sender, EventArgs e)
{
    theDataEntryForm = new DataEntryForm();
}

At this point we will leave it to the OP's (and your) imagination to picture when the instance of the DataEntryForm is shown. But of course we want to demonstrate how you would access the properties after the Form has been closed : so we put a Button on the UserControl :

    private void button2_Click(object sender, EventArgs e)
    {
        Console.WriteLine(theDataEntryForm.TextEntered);
        Console.WriteLine(theDataEntryForm.LBSelection.ToString());
    }

Note : we didn't do any "fancy" analysis of the ListBox selected indices : but we could have written out whether it was null, or how many items had been selected, etc.

Also : we didn't deal with the issue of what if the OP wants to take some action the moment the "shown Form" is closed : that's so simple : you just subscribe to the FormClosed event of the Form in the UserControl, and do what you need to do in your Event Handler code.

Finally we come to the question of why make a Public Property of type 'DataEntryForm :

Well, just consider that by exposing that "shown Form" via a Public Property in the UserControl : we allow the potential containers (probably a Form) of the UserControl instances to also have access to the values of the Controls on the "shown Form" ... which may be valuable, may save us some duplication of properties.

So, if UserControl1 is on Form1, and Form1 wants to know the Text value of the TextBox on the "shown Form" : it could be accessed like so :

this.userControl11.theDataEntryForm.TextEntered

Edit : A friend of mine wrote me to express his opinion that allowing a "higher-level" container to directly access a "component" embedded in a UserControl was a "violation" of good OOD practicem and breaks encapsulation : he issued me a moving violation ticket :) So, keep his warning in mind. From his point of view the properies should be duplicated in the UserControl with different names, and only those UserControls properties made available to the UserControl Container. My bias is to see the "UserContro/Form" as one "compound object" here, which, since the Form is exclusively used by the UserForm, justifies not duplicating the Properties /Edit

Of course we've left out checking for possibly null values of everything-under-the-sun as we all do so religiously.


here's a short example on how you could do it. It's not complete you'll have to fill in some of the blanks but it should give you an idea of how to solve your problem.

this code goes where you construct your control and you form

MyUserControl ctrl = new MyUserControl();
Action<typeYouPassBack> callBack = myUserControl.FormCallBack;
MyOptionForm form = new MyOptionForm(callBack);

the form class would then have to look something like this: (important part is the action argument)

class MyOptionForm : Form
{
  private readonly Action<typeYouPassBack> _callBack;
  public MyOptionForm(Action<typeYouPassBack> callBack)
  {
    _callBack = callBack;
    Close += form_Close;
  }

  privatre void form_close(object sender, EventARgs e)
  {
     typeYouPassBack postBackData = //populate the postback data
     _callBack(postBackData);
  }
}

the type Action is simply a delegate with the signature void f(T arg). In the above code it's expected for the user control to have amethod called 'FormCallBack' which of course can be named anything you like as long as you use the correct name when assigning it to the 'callback' variable

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜