C# - Form1 Form2 problém
Relativně často se na mém oblíbeném fóru objevuje začátečnická otázka typu :
Form1 otevřu jako dialog Form2. Jak prostřednictvím Form2 změním hodnoty ve Form1
A taky nevím, jak například zjistím obsah textboxu v okne Form1 z okna Form2.
Když si udělám v aplikaci C#, kromě form1 další formulář form2 a ně něj položím třeba prvek textBox, chtěl bych se na něj dostat i z form1
Vytvořím a rozložím tedy tento problém a vysvětlím několik z možných řešení. Problém : Mám hlavní formulář aplikace na kterým je nějakým způsobem zobrazen uživatel a chci na tlačítko zobrazit formulář s informacemi o uživateli. Tam data zmodifikovat a vrátit do hlavního formuláře jak je na obrázku :
Pojmenuji tedy hlavní formulář jako MasterForm a formulář uživatele jako UserForm. Problém rozložím do úkolů :
-
Jak dostat data z MasterForm do UserForm
- Jak dostat data z UserForm do MasterForm
A nastíním několik řešení
Veřejné uživatelské prvky
Jedno z možných řešení je uživatelským prvkům sloužící jako zdroje dat nastavit vlastnost Modifiers na public v obou formulářích. Kod by byl potom vyjádřen takto (obluha událost stisknutí tlačítka na MasterForm):
private void showAndGetUserButton_Click(object sender, EventArgs e)
{
// úkol 1
UserForm user_form = new UserForm();
user_form.NameUserTextBox.Text = this.NameUserTextBox.Text;
user_form.BirthDateDateTimePicker.Value = this.BirthDateDateTimePicker.Value;
user_form.ChildNumberTextBox.Text = this.ChildNumberTextBox.Text;
if (user_form.ShowDialog() == DialogResult.OK)
{
// úkol 2
this.NameUserTextBox.Text = user_form.NameUserTextBox.Text;
this.BirthDateDateTimePicker.Value = user_form.BirthDateDateTimePicker.Value;
this.ChildNumberTextBox.Text = user_form.ChildNumberTextBox.Text;
}
}
Jednoduché, bezpracné a zcela krátkozraké řešení. Proč krátkozraké ? Protože zpravidla uživatel má nějaké jméno. Datum narození nebude starší 200 let a nebude z budoucnosti. Počet dětí nebude záporné číslo. Nazvu toto aplikační logikou, kterou je nutnou zkontrolovat při návratu z UserForm do MasterForm. Kontrolu této logiky lze potom různě rozdělit mezi MasterForm a UserForm o čemž není primárně tento článek. Jde o to, že tento způsob jde proti dobrým programátorským mravům z hlediska zapouzdření objektu. Zbytečně zveřejňujeme prvky formuláře aniž by k tomu byl vážný důvod. Navíc můžeme potřebovat vytvářet a zobrazovat UserForm na vícero místech a třeba budeme potřebovat s počtem dětí pracovat jako s číslem, takže bychom museli všude převádět na číslo. Vysvětlím proto lepší způsob.
Properties
Rozhodně lepším způsobem řešení je pro každou naší informaci : jmého uživatele, datum narození a počet dětí použít veřejnou property, která spolupracuje z konkrétním uživatelským prvkem v každém z obou z formulářů :
public string Name
{
get
{
return nameUserTextBox.Text;
}
set
{
nameUserTextBox.Text = !string.IsNullOrEmpty(value) ? value : string.Empty;
}
}
public DateTime BirthDate
{
get
{
return birthDateDateTimePicker.Value;
}
set
{
birthDateDateTimePicker.Value = value;
}
}
public int ChildNumber
{
get
{
int child_number = int.MinValue;
if (int.TryParse(childNumberTextBox.Text, out child_number))
{
return child_number;
}
else
{
return int.MinValue;
}
}
set
{
this.childNumberTextBox.Text = value.ToString();
}
}
Naše dva úkoly potom budou vypadat takto:
// úkol 1
UserForm user_form = new UserForm();
user_form.Name = this.Name;
user_form.BirthDate = this.BirthDate;
user_form.ChildNumber = this.ChildNumber;
if (user_form.ShowDialog() == DialogResult.OK)
{
// úkol 2
this.Name = user_form.Name;
this.BirthDate = user_form.BirthDate;
this.ChildNumber = user_form.ChildNumber;
}
Takovýto kód je potom čistší, lépe spravovatelnější a hlavně ve větším měřítku srozumitelnější. I další výhody má, ale v rámci rozumné krátkosti to podrobněji popisovat nebudu.
Malý "problém" výše uvedeného přístupu je ten, že by to takto zkušenější programátor nenapsal. Ta data by zabalil do třídy uživatel a přes property by si předal jenom toho uživatele. Tedy princip stejný.
Předávání odkazů na MasterForm
Ještě jednu techniku zde zmíním. Z mého pohledu implikující spíš problém v návrhu aplikace, ale někdy se může hodit o tomto vědět.
Pokud bych chtěl pracovat v UserFormu s MasterFormem, předal bych si do UserFormu na MasterForm odkaz. Já bych to udelal konstruktorem. A to zkráceně takto:
public class UserForm:Form
{
private MasterForm masterForm;
public UserForm(MasterForm masterForm)
{
// předání odkazu
this.masterForm = masterForm;
}
public void delejNecoVMasterFormu()
{
this.masterForm.Name = “Vlášek Karel”;
}
}
public class MasterForm:Form
{
private void showAndGetUserButton_Click(object sender, EventArgs e)
{
// předání kostruktorem
UserForm user_form = new UserForm(this);
if (user_form.ShowDialog() == DialogResult.OK)
{
// tady můžu a nemusím něco dělat
}
}
}
Závěr
Chtěl jsem ukázat na cvičném příkladu několik jednoduchých možností jak si předávat data mezi formuláři. Pouze jen a o to mi šlo. Zkušený programátor by totiž problematiku zobrazení uživatele ve formulářích řešil vytvořením třídy uživatel …., ale to už je jiný příběh.
Projekt na hraní s verzi Properties pro VS 2005 je zde.
Form1Form2Problem.zip (42,81 kb)