如何从Form1到Form2(或任何其他表单)获取数据。

几乎每天在C#论坛中都会问这个问题:“我如何从Form1到Form2获得价值?” 或相反。 互联网上关于如何执行此操作的坏建议令人震惊。 本教程旨在向您展示在表单之间传递数据的更多“正确”方法。

本教程的范围仅限于在表单之间传递数据。 我们将同时查看属性和自定义事件,但将进行简要概述。 如果您需要更多信息,已经有一些出色的教程更详细地介绍了其中一些主题:

快速简便的自定义事件 构建应用 程序-第1部分 构建应用程序-第2部分

让我们从一个新的Windows Forms项目开始(尽管请注意,这些方法也可以用于WPF表单)。 我正在创建三种形式:[inline] DefaultForm [/ inline],[inline] FirstNameForm [/ inline]和[inline] LastNameForm [/ inline]。 DefaultForm是“ Form1”,即在应用程序启动时打开的窗体。

子窗体有两种类型:

模态 态(非模态) 。 从这两种信息中获取信息的方法不同,因为它们的行为不同。

无模子窗口不需要立即响应,也不会阻止您再次关注父窗体。 您可以在它们之间自由地来回切换。 无模式对话框的一个示例是Visual Studio中的“查找”(ctrl + F)对话框。

另一方面,模态对话框阻止您切换回父窗口。 他们需要回应才能继续。 模态对话框的一个示例是MessageBox。

根据您选择使用的表单类型,您将需要从中获取不同的数据。

无模

首先,我们将访问无模式表单。 表单在打开时被视为无模式

显示方法 执行不会在那条线上停止; 即使现在已显示并突出显示子窗体,该代码仍会继续执行。 我们将使用[inline] FirstNameForm [/ inline]作为无模式对话框。

由于执行不会停止,因此我们需要一种方法来知道所需值的更新时间。

定制事件就是答案。 我们喜欢使用事件而不是仅仅传递属性的原因是我们不想紧密地耦合我们的表单。 DefaultForm不需要了解更多有关FirstNameForm的知识。 这样,除了有一个事件外,它不需要了解其他任何信息。 它不需要知道属性的名称,也不必猜测何时更新属性。

另一个好处是可重用性。 当子窗口运行时,您可能希望几种形式进行更新。 这样,每个表单都可以订阅事件并以他们选择的方式处理事件。 正如该论坛的另一位专家解释的那样,这就像宾果游戏。 当画出一个数字时,那个家伙不会走在过道上并标记每个人的棋盘。 他将其喊出来(一个事件),每个人都相应地处理它(订阅者处理该事件)。

让我们创建一个自定义EventArgs类来满足我们的需求。 这个简单的类扩展了EventArgs,并具有一个名为Name的公共字符串属性。

public class NameUpdatedEventArgs : EventArgs
{
    public string Name { get; set; }
}
我们将使用该EventArgs类来传递我们的值。 现在,我们必须创建事件本身。 在FirstNameForm的类定义内,我们将添加以下代码:
public event EventHandler<NameUpdatedEventArgs> FirstNameUpdated; 
protected virtual void OnFirstNameUpdated(NameUpdatedEventArgs e)
{
    if (FirstNameUpdated != null)
        FirstNameUpdated(this, e);
}
第一行创建事件本身。 随后的方法实际上触发事件本身。 它希望您传递给它一个NameUpdatedEventArgs,它将用作事件的参数之一。 因此,当我们希望触发FirstNameUpdated事件时,我们调用OnFirstNameUpdated方法。

现在我们有了事件的代码,我们需要添加逻辑来调用该事件。 在我的示例中,我们将在用户单击按钮时更新值:

private void UpdateButton_Click(object sender, EventArgs e)
{
    string newFirstName = firstNameTextBox.Text;
    NameUpdatedEventArgs nuea = new NameUpdatedEventArgs();
    nuea.Name = newFirstName;
    OnFirstNameUpdated(nuea);
}
首先,我们得到了新的名字。 然后,我们创建一个新的NameUpdateEventArgs对象。 然后,我们将新的名字分配给args的Name属性。 最后,我们调用触发FirstNameUpdated事件的方法。

现在,我们完成了FirstNameForm。 它设置为广播其事件,不需要其他任何工作。

在DefaultForm中,我们需要处理事件。 在此示例中,我们将在打开DefaultForm时立即打开子窗口,因此我们将在DefaultForm的构造函数中创建并显示FirstNameForm:

public DefaultForm()
{
    InitializeComponent();
    FirstNameForm fnf = new FirstNameForm();
    fnf.FirstNameUpdated += new EventHandler<NameUpdatedEventArgs>(fnf_FirstNameUpdated);
    fnf.Show();
}
方法的第一行是Visual Studio添加到每种表单中以设置所有GUI组件的标准方法调用。 下一行创建FirstNameForm的新实例。

下一行添加了一个事件处理程序**。 最后一个以无模式的方式显示窗口。

**有关添加事件处理程序的快速说明:Visual Studio将为您完成大部分工作。 输入行首,直到+ =:

并且Visual Studio要求您推送TAB。 推它:

并为您完成了生产线。 但是它希望您再次按Tab。 做到:

它也为您创建处理程序方法。 确实确实使事件处理程序不再需要猜测和记忆。

VS为我们创建的方法将是每次触发FirstNameUpdated时执行的代码。 让我们填写:

void fnf_FirstNameUpdated(object sender, NameUpdatedEventArgs e)
{
    if (e != null && e.Name != null)
        firstNameLabel.Text = e.Name;
}
还记得我们将名称添加到NameUpdatedEventArgs吗? 在变量[inline] e [/ inline]中。 首先,我们检查以确保e及其属性不为null,然后从e中获取Name值并将其分配给标签。

就是这样。 运行程序时,我们会在更新之前看到以下内容:

并在更新后:

除非关闭它,否则FirstNameDialog不会消失。

模态

接下来,我们将访问无模式表单。 表格被视为moda; 当它被打开时

.ShowDialog方法。 执行将停止在该行,直到关闭子窗体。 ShowDialog方法返回DialogResult对象。 我们将使用[inline] LastNameForm [/ inline]作为模式对话框。

现在,模式对话框与其他类型的模型有所不同。 通常,它们的重点和目的会受到限制,并且打开父窗体时会阻止其执行,\因此可以将它们与父窗体紧密耦合。 在一定程度上。 当然,两种形式都不应该知道另一种形式的UI控件。 这是在网络上“使您的TextBox公开”的最常见建议。

不要那样做! 。 而是,将您的TextBox的Text属性包装在一个公共属性中。 这是我们在LastNameForm中执行的操作(这将添加到类LastNameForm中):
public string LastName
{
    get
    {
        return lastNameTextBox.Text;
    }
}
现在,我们只处理一个字符串,而不是处理整个TextBox。

现在,由于我们不需要知道子窗体何时关闭的方法(因为ShowDialog是阻塞调用),我们只需要确保在获得所需的窗体时就关闭窗体。 在此示例中,当有人单击标有“确定”的按钮时,我将关闭表单:

private void OkButton_Click(object sender, EventArgs e)
{
    this.DialogResult = DialogResult.OK;
    this.Close();
}
我们将DialogResult设置为OK,以使其他窗体知道它不是被强制关闭或取消的。

这就是LastNameDialog所要做的。 现在,我们需要看一下创建对话框并获取其值。

在DefaultForm中,当用户单击按钮时,我们将启动LastNameDialog:

private void GetLastNameButton_Click(object sender, EventArgs e)
{
    LastNameForm lnf = new LastNameForm();
    DialogResult res = lnf.ShowDialog();
    if (res == DialogResult.OK)
        lastNameLabel.Text = lnf.LastName;
}
第一行创建一个新的LastNameForm。 下一个将其称为“模态”对话框,并在关闭后检索其响应。 接下来的几行测试以查看DialogResult是否为“ OK”,如果是,则使用LastName属性的值作为DefaultForm上的标签。

涉及模态对话框时,这实际上就是所有内容。 请记住,这种方式很少涉及,但是模式对话框阻止了主窗体的执行,并且您不能从一种切换到另一种。 因此,您必须做出明智选择的选择。

使用时的外观如下。 单击确定之前:

单击确定后:

请注意,当我们单击“确定”时,对话框消失了。

将值传递给新表单

另一个非常常见的相关问题涉及将值传递给

表格。 一种非常简单的方法是记住表单只是类,并且所有类都具有构造函数。 确实,调用[inline] new Form1()[/ inline]与[inline] new Random()[/ inline]或任何其他类没有什么不同。 并且由于此表单是您正在创建的类,因此您可以控制构造函数及其参数。

我将继续前面的示例。 我们将添加一个名为[inline] DisplayNameForm [/ inline]的表单。 该表单只是显示表单,而不是输入表单,因此我们不必担心事件或类似的事情。 但是我们需要它来显示名称,因此在创建时需要两个名称。 通常,创建表单时,将使用默认构造函数创建它:

public DisplayNameForm()
{
    InitializeComponent();
}
但是,仅仅因为它以这种方式开始并不意味着它就必须保持这种方式。 让我们向构造函数添加一些参数,以及一些分配逻辑。
public DisplayNameForm(string firstName, string lastName)
{
    InitializeComponent();
    firstNameLabel.Text = firstName;
    lastNameLabel.Text = lastName;
}
现在,表单需要同时创建一个名字和一个姓氏。 并且在创建时,会将这些值分配给表单上的某些标签。

当然,这改变了我们创建和调用表单的方式。 对于此示例,在DisplayForm中,单击按钮时将显示此DisplayNameForm:

private void DisplayNameButton_Click(object sender, EventArgs e)
{
    string firstName = firstNameLabel.Text;
    string lastName = lastNameLabel.Text;
    DisplayNameForm dnf = new DisplayNameForm(firstName, lastName);
    dnf.Show();
}
前两行收集名称。 第三是新表格的实际创建。 注意,我们将名称作为构造函数的参数提供。 它们与构造函数定义中的参数匹配。 最后,我们将其显示为其他任何形式。 结论

希望您喜欢本教程。 我尝试使它尽可能简单,同时仍然遵循声音设计和面向对象的原则。

这篇文章是我的

博客

From: https://bytes.com/topic/c-sharp/insights/904861-how-get-data-form1-form2-any-other-forms

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值