Como persisto uma variável BYREF no formulário de diálogo .NET WinForms?
-
02-07-2019 - |
Pergunta
Estou criando um formulário de "seletor de departamento" que servirá como uma forma pop -up modal com muitas das minhas formas "primárias" de um aplicativo Winforms. Idealmente, o usuário clicará em um ícone ao lado de uma caixa de texto que exibirá o formulário, eles selecionarão o departamento de que precisam e, quando clicarem em OK, a caixa de diálogo fechará e eu terei o valor selecionado para mim para que eu Atualize a caixa de texto com.
Eu já fiz a rota com a passagem do proprietário da caixa de diálogo para o formulário de diálogo e ter o evento OK Button Click, faça a atualização adequada, mas isso me obriga a fazer um Directcast para o tipo de formulário e só posso reutilizar o Picker no formulário atual.
Consegui usar uma variável BYREF no construtor e atualizar com sucesso um valor, mas funciona apenas no construtor. Se eu tentar atribuir o valor BYRef a alguma variável interna na aula de seleção do departamento, perco o aspecto de referência dela. Este é o meu código básico anexado ao meu formulário:
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
Alguém pode me dizer o que estou perdendo aqui ou uma abordagem diferente para fazer isso acontecer?
NOTA: O exemplo de código está no vb.net, mas também aceitarei as respostas C#. 8^d
Solução
Nesses casos, eu geralmente também
- Escreva uma função ShowDialog que faça o que eu quero (por exemplo, retorne o valor) ou
- Apenas deixe o resultado ser uma propriedade na caixa de diálogo. É assim que as caixas de diálogo comuns de arquivo fazem isso no BCL. O chamador deve então ler a propriedade para obter o resultado. Tudo bem na minha opinião.
Você também pode combinar esses métodos, tornando o valor do resultado uma propriedade na caixa de diálogo e criando um método ShowDialog que retorna esse valor de propriedade, como Byref que desejar ou como um valor de retorno, dependendo de suas necessidades.
Vou adicionar isso como uma instrução de uso, por exemplo (desculpe, nenhum VB aqui, e você disse que C# é bem -vindo):
using (var dlg = new DeptPicker()) {
if (dlg.ShowDialog() == DialogResult.OK) {
myTextBoxOrWhatEver.Text = dlg.TargetResult;
}
}
Na própria caixa de diálogo, basta fazer isso:
void okButton_Click(object sender, EventArgs e)
{
TargetResult = whatever; // can also do this when the selection changes
DialogResult = DialogResult.OK;
Close();
}
Eu não usei a nova implementação do showDialog nesta amostra.
Outras dicas
O problema é que a atribuição de TargetResult no construtor está usando a string como referência. A sequência M_TARGETRESULT é apenas uma cópia da string ref, não uma referência à string original.
Quanto a como fazer um "ponteiro" para o original, eu não sei.
Isso é ainda mais difícil pelo fato de o vb.net não suportar blocos de código inseguros, para que você não possa fazer uma referência de ponteiro à string.
Você pode passar na referência da caixa de texto para o formulário modal.
Deixe o usuário escolher qualquer departamento. Quando o usuário clicar OK, defina a propriedade de texto da caixa de texto referida como o texto ou o ID do departamento escolhido (depende do que você precisa)
Estou usando o código fornecido por você.
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
' 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_TargetTextBox.Text = "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
Public Class DeptPicker
dim dlgResult as DialogResult
Public Function GetSelectedDepartment() As String
Me.Show vbModal
If (dlgResult = Windows.Forms.DialogResult.OK) Then
return "selected department string here"
Else
return "sorry, you didnt canceled on the form"
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
Nota: Eu não testei isso. Espero que você tenha uma ideia do que quero dizer.
Oregonghost: Isso parece melhor?
O usuário pode ligar para o novo deptpicker (). GetSelectedDepartment (). Eu não sabia que não preciso postar a resposta novamente e poderia usar a mesma postagem.
Obrigado Oregonghost. Agora, parece bem?
Isso pode funcionar:
// 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();