J'ai un formulaire principal (appelons-le frmHireQuote) qui est un enfant d'un formulaire principal MDI (frmMainMDI), qui affiche un autre formulaire (frmImportContact) via ShowDialog () lorsqu'un clic est effectué sur un bouton.
Lorsque l'utilisateur clique sur 'OK' sur frmImportContact, je souhaite transmettre quelques variables de chaîne à des zones de texte sur frmHireQuote.
Notez qu'il peut y avoir plusieurs instances de frmHireQuote. Il est évidemment important que je revienne à l'instance qui a appelé cette instance de frmImportContact.
Quelle est la meilleure méthode pour faire cela?
Créez des propriétés publiques sur votre sous-formulaire
public string ReturnValue1 {get;set;}
public string ReturnValue2 {get;set;}
puis placez-le dans votre sous-formulaire
private void btnOk_Click(object sender,EventArgs e)
{
this.ReturnValue1 = "Something";
this.ReturnValue2 = DateTime.Now.ToString(); //example
this.DialogResult = DialogResult.OK;
this.Close();
}
Puis dans votre frmHireQuote formulaire , lorsque vous ouvrez le sous-formulaire
using (var form = new frmImportContact())
{
var result = form.ShowDialog();
if (result == DialogResult.OK)
{
string val = form.ReturnValue1; //values preserved after close
string dateString = form.ReturnValue2;
//Do something here with these values
//for example
this.txtSomething.Text = val;
}
}
De plus, si vous souhaitez annuler le sous-formulaire , vous pouvez simplement ajouter un bouton au formulaire et définir son DialogResult to Cancel
et vous pouvez également définir la propriété CancelButton du formulaire sur ledit bouton - ceci permettra à la touche d'échappement d'annuler le formulaire.
Je crée normalement une méthode statique sur formulaire/dialogue, que je peux appeler. Cela renvoie la réussite (bouton OK) ou l'échec, ainsi que les valeurs à renseigner.
public class ResultFromFrmMain {
public DialogResult Result { get; set; }
public string Field1 { get; set; }
}
Et sur le formulaire:
public static ResultFromFrmMain Execute() {
using (var f = new frmMain()) {
var result = new ResultFromFrmMain();
result.Result = f.ShowDialog();
if (result.Result == DialogResult.OK) {
// fill other values
}
return result;
}
}
Pour appeler votre formulaire
public void MyEventToCallForm() {
var result = frmMain.Execute();
if (result.Result == DialogResult.OK) {
myTextBox.Text = result.Field1; // or something like that
}
}
J'ai trouvé un autre petit problème avec ce code ... ou du moins c'était problématique lorsque j'ai essayé de le mettre en œuvre.
Les boutons de frmMain ne renvoient pas de valeur compatible. À l’aide de VS2010, j’ai ajouté ce qui suit et tout a bien fonctionné.
public static ResultFromFrmMain Execute() {
using (var f = new frmMain()) {
f.buttonOK.DialogResult = DialogResult.OK;
f.buttonCancel.DialogResult = DialogResult.Cancel;
var result = new ResultFromFrmMain();
result.Result = f.ShowDialog();
if (result.Result == DialogResult.OK) {
// fill other values
}
return result;
}
}
Après avoir ajouté les deux valeurs de bouton, la boîte de dialogue a bien fonctionné! Merci pour l'exemple, ça m'a vraiment aidé.
Je viens de mettre quelque chose dans le constructeur par référence, afin que le sous-formulaire puisse changer sa valeur et que le formulaire principal puisse obtenir un objet nouveau ou modifié à partir du sous-formulaire.
Si vous souhaitez transmettre des données à form2
de form1
sans passer comme une nouvelle form(sting "data");
Faire comme ça dans la forme 1
using (Form2 form2= new Form2())
{
form2.ReturnValue1 = "lalala";
form2.ShowDialog();
}
en forme 2 ajouter
public string ReturnValue1 { get; set; }
private void form2_Load(object sender, EventArgs e)
{
MessageBox.Show(ReturnValue1);
}
Vous pouvez aussi utiliser la valeur dans form1
comme si vous voulez échanger quelque chose dans form1
juste en forme1
textbox.Text =form2.ReturnValue1
Vous devez d’abord définir l’attribut dans form2 (enfant) et le mettre à jour dans form2 ainsi que depuis form1 (parent):
public string Response { get; set; }
private void OkButton_Click(object sender, EventArgs e)
{
Response = "ok";
}
private void CancelButton_Click(object sender, EventArgs e)
{
Response = "Cancel";
}
Appel de form2 (enfant) à partir de form1 (parent):
using (Form2 formObject= new Form2() )
{
formObject.ShowDialog();
string result = formObject.Response;
//to update response of form2 after saving in result
formObject.Response="";
// do what ever with result...
MessageBox.Show("Response from form2: "+result);
}
Je soulève un événement dans le formulaire en définissant la valeur et je m'inscris à cet événement dans le (s) formulaire (s) devant traiter le changement de valeur.
les délégués sont la meilleure option pour envoyer des données d'un formulaire à un autre.
public partial class frmImportContact : Form
{
public delegate void callback_data(string someData);
public event callback_data getData_CallBack;
private void button_Click(object sender, EventArgs e)
{
string myData = "Top Secret Data To Share";
getData_CallBack(myData);
}
}
public partial class frmHireQuote : Form
{
private void Button_Click(object sender, EventArgs e)
{
frmImportContact obj = new frmImportContact();
obj.getData_CallBack += getData;
}
private void getData(string someData)
{
MessageBox.Show("someData");
}
}
J'utilise beaucoup MDI, je l'aime beaucoup plus (où il peut être utilisé) que plusieurs formes flottantes.
Mais pour en tirer le meilleur parti, vous devez maîtriser vos propres événements. Cela rend la vie tellement plus facile pour vous.
Un exemple squelettique.
Avoir vos propres types d'interruption,
//Clock, Stock and Accoubts represent the actual forms in
//the MDI application. When I have multiple copies of a form
//I also give them an ID, at the time they are created, then
//include that ID in the Args class.
public enum InteruptSource
{
IS_CLOCK = 0, IS_STOCKS, IS_ACCOUNTS
}
//This particular event type is time based,
//but you can add others to it, such as document
//based.
public enum EVInterupts
{
CI_NEWDAY = 0, CI_NEWMONTH, CI_NEWYEAR, CI_PAYDAY, CI_STOCKPAYOUT,
CI_STOCKIN, DO_NEWEMAIL, DO_SAVETOARCHIVE
}
Ensuite, votre propre type Args
public class ControlArgs
{
//MDI form source
public InteruptSource source { get; set; }
//Interrupt type
public EVInterupts clockInt { get; set; }
//in this case only a date is needed
//but normally I include optional data (as if a C UNION type)
//the form that responds to the event decides if
//the data is for it.
public DateTime date { get; set; }
//CI_STOCKIN
public StockClass inStock { get; set; }
}
Puis utilisez le délégué dans votre espace de noms, mais en dehors d'une classe
namespace MyApplication
{
public delegate void StoreHandler(object sender, ControlArgs e);
public partial class Form1 : Form
{
//your main form
}
Désormais, soit manuellement, soit à l'aide de l'interface graphique, demandez à MDIparent de répondre aux événements des formulaires enfants.
Mais avec vos owr Args, vous pouvez réduire cela à une seule fonction. et vous pouvez avoir une disposition pour interrompre les interruptions, ce qui est bon pour le débogage, mais peut aussi être utile autrement.
Il suffit que tous vos codes d’événement mdiparents pointent vers une fonction,
calendar.Friday += new StoreHandler(MyEvents);
calendar.Saturday += new StoreHandler(MyEvents);
calendar.Sunday += new StoreHandler(MyEvents);
calendar.PayDay += new StoreHandler(MyEvents);
calendar.NewYear += new StoreHandler(MyEvents);
Un simple mécanisme de commutation suffit généralement à transmettre les événements aux formulaires appropriés.
Tout ce dont vous avez besoin est d’ajouter le format "d", comme ceci:
private void NewAdmin_Form3_Load_1(object sender, EventArgs e)
{
DateTime today = DateTime.Today;
DateTime DateOnly = today.Date;
DateTime answer = DateOnly.AddDays(90);
ExitDateAdmin.Text = answer.Date.ToString("d");
}