如何将ByRef变量保留在.NET WinForms对话框窗体中?

3
我正在创建一个“部门选择器”表单,它将作为我的Winforms应用程序中许多“主要”表单的模态弹出表单。理想情况下,用户将点击文本框旁边的图标,然后弹出该表单,他们将选择所需的部门,当他们单击“确定”时,对话框将关闭,我将有所选值以更新文本框。
我已经通过将对话框框架的所有者传递到对话框表单并使OK按钮单击事件执行正确的更新路线,但这迫使我进行DirectCast到表单类型,因此我只能在当前表单上重复使用选择器。
我已经能够在构造函数中使用ByRef变量并成功更新值,但它仅在构造函数中有效。如果我尝试将ByRef值分配给部门选择器类中的某个内部变量,则会失去引用方面。这是我附加到我的表单的基本代码:
Public Class DeptPicker

   Private m_TargetResult As String

   Public Sub New(ByRef TargetResult As String)

      InitializeComponent()

      ' This works just fine, my "parent" form has the reference value properly updated.
      TargetResult = "Booyah!"

      ' Once I leave the constructor, m_TargetResult is a simple string value that won't update the parent
      m_TargetResult = TargetResult

   End Sub

   Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click

      DialogResult = Windows.Forms.DialogResult.OK

      ' I get no love here. m_TargetResult is just a string and doesn't push the value back to the referenced variable I want.
      m_TargetResult = "That department I selected."
      Me.Close()

   End Sub

   Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click

      DialogResult = Windows.Forms.DialogResult.Cancel
      Me.Close()

   End Sub

End Class

有人可以告诉我我错过了什么或者有其他方法可以实现这个吗?

注意:代码示例使用VB.NET,但我也接受任何C#的答案。8^D

5个回答

4
在这种情况下,我通常会执行以下操作之一:
  • 编写一个ShowDialog函数以实现我想要的功能(例如返回值)。
  • 在对话框中将结果作为属性。这是BCL中常见文件对话框的做法。然后,调用者必须读取该属性才能获取结果。我认为这样很好。
您还可以通过将结果值作为对话框中的属性,并创建一个ShowDialog方法来组合这些方法,以返回该属性的值。根据您的需求,返回值可以是ByRef或普通返回值。
例如,我将其添加为用法说明(抱歉,这里没有VB,您说C#也可以):
using (var dlg = new DeptPicker()) {
    if (dlg.ShowDialog() == DialogResult.OK) {
        myTextBoxOrWhatEver.Text = dlg.TargetResult;
    }
}

在对话框本身中,只需执行以下操作:
void okButton_Click(object sender, EventArgs e)
{
    TargetResult = whatever; // can also do this when the selection changes
    DialogResult = DialogResult.OK;
    Close();
}

在此示例中,我未使用新的 ShowDialog 实现。


现在我要表现出我的无知了。如何让ShowDialog方法返回除OK、Cancel等对话框结果枚举之外的值? - Dillie-O
在您的部门选择器表单中将m_TargetResult公开为属性。然后,当用户单击“确定”时,隐藏(Hide())选择器表单而不是关闭(Close())它。然后,您可以获得:x = DepartmentPickerForm.TargetResult。最后,在访问所需内容后关闭该表单。 - AR.
您需要将最后的评论发布为答案。我认为这样会起作用,并且我想正确标记它,以便大家可以在不查看评论的情况下阅读。 - Dillie-O
你不需要隐藏对话框,关闭即可。但请确保在窗体关闭时不要处理该属性,因为这是在关闭期间发生的。 - OregonGhost
看一下我添加的示例。这就是我在上一个应用程序中几次完成的方式,也基本上是打开文件对话框等工作的方式。 - OregonGhost
如果您使用ShowDialog(),则在调用Close()时对话框不会被释放,否则它会被释放。请参阅http://msdn.microsoft.com/en-us/library/system.windows.forms.form.close.aspx。当然,在上面的示例中,对话框将在`using`块结束时被释放,因此您需要在该块内访问对话框的属性。或者,您可以不使用`using`,并在访问所需属性后自行释放对话框。 - Jason S

0
问题在于在构造函数中分配TargetResult时使用了字符串作为引用。m_TargetResult字符串只是ref字符串的副本,而不是对原始字符串的引用。
至于如何创建指向原始字符串的“指针”,我不知道。
更加困难的是,VB.NET不支持不安全代码块,因此无法将指针引用指向字符串。

0

您可以将文本框的引用传递给模态窗体。

让用户选择任何部门。当用户单击“确定”时,将所引用文本框的文本属性设置为所选部门的文本或ID(取决于您需要什么)

我正在使用您提供的代码。


Public Class DeptPicker

   Private m_TargetTextBox As TextBox
Public Sub New(ByRef TargetTextBox As TextBox) InitializeComponent()
m_TargetTextBox = TargetTextBox
End Sub
Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click
DialogResult = Windows.Forms.DialogResult.OK
' 这里没有得到支持。m_TargetResult只是一个字符串,并不能将值推回我想要的引用变量。 m_TargetTextBox.Text = "我选择的那个部门。" Me.Close()
End Sub
Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click
DialogResult = Windows.Forms.DialogResult.Cancel Me.Close()
End Sub
End Class

将对话框与调用者紧密耦合在一起,我不建议这样做。 - OregonGhost

0
公共类DeptPicker Dim dlgResult As DialogResult
Public Function GetSelectedDepartment() As String Me.Show vbModal If (dlgResult = Windows.Forms.DialogResult.OK) Then Return "在此选择部门字符串" Else Return "抱歉,您没有在表单上取消" End If End Function
Private Sub btnOK_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnOK.Click dlgResult = Windows.Forms.DialogResult.OK Me.Close() End Sub
Private Sub btnCancel_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCancel.Click dlgResult = Windows.Forms.DialogResult.Cancel Me.Close() End Sub End Class
注意:我还没有测试过。希望你能理解我的意思。
OregonGhost: 这样看起来更好了吗?
用户可以调用new DeptPicker().GetSelectedDepartment()。 我不知道我不需要再次发布答案,而是可以使用相同的帖子。
谢谢OregonGhost。现在看起来还好吗?

是的,虽然这个例子未提及如何将对话框中的结果值传递给函数,所以错过了非常重要的部分。 - OregonGhost
哦,你知道你可以编辑你的第一篇帖子,而不是发表新的吗? - OregonGhost

0

这可能有效:

    // This code in your dialog form.  Hide the base showdialog method 
    // and implement your own versions
    public new string ShowDialog() {
        return this.ShowDialog(null);
    }

    public new string ShowDialog(IWin32Window owner) {
        // Call the base implementation of show dialog
        base.ShowDialog(owner);

        // You get here after the close button is clicked and the form is hidden.  Capture the data you want.
        string s = this.someControl.Text;

        // Now really close the form and return the value
        this.Close();
        return s;
    }

    // On close, just hide.  Close in the show dialog method
    private void closeButton_Click(object sender, EventArgs e) {
        this.Hide();
    }

    // This code in your calling form
    MyCustomForm f = new MyCustomForm();
    string myAnswer = f.ShowDialog();

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接