简体   繁体   English

从用户控件中打开Winform并将值传递回用户控件

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

我想知道是否可以让用户控件打开一个允许用户选择其上的选项的winform,然后在他关闭窗体时-将他选择的选项/值返回给用户控件?

Why not create some public properies on your dialog form, and access them from the UserControl once the dialog has been closed? 为什么不在对话框表单上创建一些公共属性,并在对话框关闭后从UserControl访问它们?

public class OptionsForm : Form
{
    // ...

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

And then, within the UserControl: 然后,在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. 请将此答案视为对史蒂夫·格雷特雷克斯(Steve Greatrex)现在接受的答案的“扩展评论”:评论太久了,我想展示一些选择,并为口味添加一些“风味”。 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 : 假设:如果我较早读过这个问题,我将通过对以下各点的评论来询问OP:

  1. the OP did not specify whether the Form to be "shown" was to be shown modally or not. OP未指定是否以模态方式显示要“显示”的表格。

  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. OP并未指定是否在每次显示表单时都重新创建该表单,或者是否应创建并重新使用该表单的一个实例。

  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. OP写道:“打开一个允许用户选择其上的选项的Winform ... snip ...“返回他选择的选项/值”:Steve的代码并未确切显示公开设置为Public的属性的设置,但是我我将假设OP可能旨在表示用户与显示的表单上的某些控件进行了交互,并且他所指的“选项/值”是表单上的控件的属性:就像最终用户键入一些TextBox中的文本或ListBox中的选定索引,其SelectionMode设置为允许多项选择的两个选择之一。

  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. OP并没有说是否希望该表单(如果重复使用)保留如上所述的最终用户与该表单上的控件的最后交互结果。

  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." OP并没有说明UserControl所显示的Form是否将其Parent属性设置为其他有效容器:我假设它们意味着Form显示为“无父母”。

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. 如果OP希望以模态形式显示Form :为了使Steve的代码正常工作,则必须取消Form的“ ControlBox”作为选项,并在Form上将“ DialogResult”属性设置为“ OK”的Button放进去, ”,并且其“点击事件关闭了表单:如果不满足这些条件,史蒂夫代码中的ShowDialog结果将永远不会返回”确定”,并且属性的值也永远不会被设置。 Note : closing a Form via the 'ControlBox will return a DialogResult of "Cancel." 注意:通过“ ControlBox”关闭表单将返回DialogResult“取消”。

  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. 让我们考虑一下,可能有充分的理由将创建的Form公开为UserControl的Public成员。

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. 我们的“显示的表单”将具有一个TextBox和一个ListBox,允许进行多个选择:我们的目标是在TextBox中公开Text,在ListBox中公开当前的索引选择。

  1. Form has a ControlBox : does not require a Button to close as described above. 窗体具有一个ControlBox:不需要如上所述关闭Button。

  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 : 在“显示的表单”中 ,我们将其命名为'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) 在UserControl中,我们创建一个类型为'DataEntryform'的公共属性(原因说明)

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 我们在UserControl的Load事件中创建DataEntryForm的实例,并将其分配给public属性

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. 此时,当显示DataEntryForm的实例时,我们将把它留给OP(和您)的想象。 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 : 但是当然,我们想演示在关闭窗体后如何访问属性:因此我们在UserControl上放置了一个Button:

    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. 注意:我们没有对ListBox选定的索引做任何“花哨的”分析:但是我们可以写出它是否为空,或者选择了多少项,等等。

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. 另外:我们没有处理如果OP希望在“显示的窗体”关闭时希望采取某些措施的问题:如此简单:您只需在UserControl中订阅Form的FormClosed事件,然后执行您需要在事件处理程序代码中执行的操作。

Finally we come to the question of why make a Public Property of type 'DataEntryForm : 最后,我们来问一个问题,为什么要设置'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. 好吧,请考虑通过在UserControl中通过公共属性公开“显示的表单”:我们允许UserControl实例的潜在容器(可能是表单)也可以访问“显示的表单”上的控件的值...这可能很有价值,可以为我们节省一些属性的重复。

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 : 因此,如果UserControl1在Form1上,并且Form1想知道“显示的窗体”上TextBox的Text值:可以这样访问它:

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. 编辑:我的一个朋友写信给我表达他的观点,即允许“更高级别”的容器直接访问嵌入在UserControl中的“组件”是对良好OOD习惯的“违反”,并且破坏了封装:违规罚单:)因此,请牢记他的警告。 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. 从他的角度来看,属性应该在UserControl中以不同的名称重复,并且只有那些对UserControl容器可用的UserControls属性。 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 我的偏见是将“ UserContro / Form”视为一个“复合对象”,由于Form是UserForm专门使用的,因此它有理由不复制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). Action类型只是具有签名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 在上面的代码中,期望用户控件具有一种名为“ FormCallBack”的方法,当然,只要将其分配给“ callback”变量时使用正确的名称,该方法就可以随意命名

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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