2012-02-27 14 views
12

स्टैक ओवरव्लो पर बहुत सारे प्रश्न हैं कि फ़ॉर्म 1 को छुपाने और फॉर्म 2 दिखाने के तरीके से पूछें।रूपों को दिखाने और छिपाने के लिए बहु-स्वरूप अनुप्रयोगों के लिए सर्वोत्तम अभ्यास?

// Program.cs 
Application.Run(new Form1()); 
// Form1.cs 
Form2 form2 = new Form2(); 
form2.Show(); 
this.Hide(); 

1))

// Program.cs 
Form1 form1 = new Form1(); 
Form2 form2 = new Form2(); 
form1.Show(); 
form2.Show(); 
Application.Run(); 

...etc..

मैं # की तरह एक साधारण डिस्पोजेबल समाधान के लिए नहीं देख रहा हूँ: और, आम तौर पर, कुछ अलग जवाब पैदा 1। मैं सबसे अच्छा फॉर्म प्रबंधन प्रथाओं की तलाश में हूं। 5-8 रूपों वाला एक आवेदन, एक-दूसरे को खोलना और बंद करना - इन रूपों को प्रबंधित करने का सबसे अच्छा तरीका क्या है?

मेरा विचार प्रत्येक एक (आलसी?) सिंगलटन फार्म बनाने के लिए और उन्हें किसी प्रकार की FormsManager कक्षा में दफनाने (# 2 समाधान की तरह लेकिन ++) के लिए किया गया था। और फिर व्यक्तिगत रूप FormsManager.GetForm<WelcomeDialog>() जैसे कुछ कह सकते हैं।

लेकिन मैं सोच रहा था कि अधिक अनुभव वाले लोग क्या उपयोग करते हैं। फिर, इन समाधानों को त्वरित हैक नहीं होना चाहिए। वे डिजाइन उन्मुख, शायद आर्किटेक्चरल, और दीर्घकालिक समाधान होना चाहिए।

संपादन:

यह एक बहुत सामान्य प्रश्न (ताकि आवश्यकताओं सुंदर खुले हैं) किसी को भी, जो एक ही मुसीबत हो सकता है के लिए है। हालांकि मेरी स्थिति के लिए विशिष्ट, मुझे स्टार्टअप पर दिखाए गए कई रूपों की आवश्यकता नहीं है। इसके अलावा, मेरे पास कोई एमडीआई रूप नहीं है। मेरे पास कुछ मोडल रूप हो सकते हैं, लेकिन वे अधिकतर गैर-मोडल हैं।

+0

आवश्यकताएं क्या हैं एक और रूप बनाने की है? आप स्टार्टअप पर कई रूपों को दिखाना चाहते हैं? एक बार एप्लिकेशन शुरू हो जाने के बाद, फॉर्म शो/छुपा रणनीति क्या है जो आप चाहते हैं (मोडल फॉर्म, एकाधिक रूप, एमडीआई फॉर्म ...)? – ken2k

+0

तो, मुझे स्टार्टअप पर दिखाए गए कई रूपों की आवश्यकता नहीं है। एक बार एप्लिकेशन शुरू हो जाने के बाद, फॉर्म शो/छुपा रणनीति बस कई रूपों (गैर-एमडीआई) है। एक या दो मोडल रूप हो सकते हैं। – Jason

उत्तर

5

मैं यहां सामान्य तरीके से जवाब दे रहा हूं।

मुझे नहीं लगता कि एक सिंगलटन पैटर्न फॉर्म प्रबंधन के साथ अच्छी तरह फिट होगा। आम तौर पर, आप फ़ॉर्म में कुछ संदर्भ पैरामीटर पास करना चाहते हैं, और आप एक ही रूप के कई उदाहरण खोलना चाहेंगे। तो एक सिंगलटन अच्छी तरह से आईएमओ फिट नहीं है।

मुझे लगता है कि फॉर्म प्रबंधन सरल होना चाहिए।

उदाहरण के लिए

, यदि आप किसी अन्य प्रकार से एक मॉडल प्रपत्र प्रदर्शित करना चाहते हैं, मैं वास्तव में कुछ सरल लिखते थे:

private void button1_Click(object sender, EventArgs e) 
{ 
    using (ModalForm1 frm = new ModalForm1(myParam)) 
    { 
     frm.ShowDialog(); 

     if (frm.MyResultProperty == ...) 
     { 
      // Do some job here 
     } 
    } 
} 

बेशक आपको कुछ इंटरफ़ेस/जेनरिक वाक्य रचना लिख ​​सकता है में एक छोटे से कोड दोहराव से बचने के मामले आप मोडल रूपों का एक बहुत प्रदर्शित करना चाहते हैं:

public interface IFormResult<T> 
{ 
    T Result { get; set; } 
} 

public class ModalForm1 : Form, IFormResult<string> 
{ 
    public ModalForm1() 
    { 
     InitializeComponent(); 

     this.Result = "My result"; 
    } 

    public string Result { get; set; } 
} 

private void button1_Click(object sender, EventArgs e) 
{ 
    string res = ShowModalForm<ModalForm1, string>(); 
} 

private static T2 ShowModalForm<T1, T2>() 
    where T1 : Form, IFormResult<T2>, new() 
{ 
    using (T1 form = new T1()) 
    { 
     form.ShowDialog(); 

     return form.Result; 
    } 
} 

लेकिन ईमानदारी से, मुझे लगता है कि यह थोड़ा overingeneered है।

दूसरा बिंदु: यदि आपका फॉर्म बिल्कुल इस विशिष्ट व्यवहार का पालन नहीं करता है (ShowDialog() तो Result संपत्ति सेट है), तो आपको एक और इंटरफेस लिखना होगा ... आदि।

यदि इस प्रकार का वाक्यविन्यास (जेनेरिक, इंटरफेस ... आदि) लिखित कोड की रेखाओं की संख्या को कम नहीं करता है या जटिलता या रखरखाव (और स्पष्ट रूप से हम यह नहीं कह सकते कि यह वास्तव में यहां मामला है) , तो यह बहुत बेकार आईएमओ है।


संपादित करें:

फार्म प्रबंधन वास्तव में आपके उपयोग के मामले पर निर्भर करता है।

  • आप कहते हैं कि 20 रूपों है कि एक ही समय में प्रदर्शित किया जा सकता है, तो आप एक FormManager अवधारणा के बारे में सोच चाहिए (या बेहतर: कैसे संभव खोला रूपों के लिए संख्या को कम करने के द्वारा उपयोगकर्ता अनुभव को बेहतर बनाने के बारे में सोचना)
  • आप अपेक्षाकृत सरल कुछ (एक ही समय + 3-4 संभव मोडल रूपों में 2-3 मोडहीन रूपों) है, तो मैं उन रूपों का प्रबंधन करने के जटिल कोड नहीं लिखेंगे।

आम तौर पर, फार्म का है कि आवेदन (अर्थात रूप है कि कार्यक्रम बंद हो जाता है, जब बंद कर दिया जो रूप है कि Application.Run() की एक पैरामीटर है) शुरू करने के लिए प्रयोग किया जाता है अन्य रूपों की जिम्मेदार है। आपके पास एक मुख्य रूप है, और गुणक बच्चे बनाते हैं। तो अपने मामले वास्तव में अलग है, तो शायद कुछ होशियार लिखने के लिए है, लेकिन यह अपने मामले पर निर्भर करेंगे। मुझे नहीं लगता कि एक रूप प्रबंधन के सामान्य समस्या पैदा करने वाले के लिए एक सामान्य अच्छा जवाब दे सकता है है।

ईमानदारी से, यदि आप वास्तव में कुछ पोषणीय चाहते हैं, को कम करने के रूपों है कि एक ही समय में दिखाया जा सकता है की संख्या की कोशिश (जितना संभव हो उतना)। एक ही समय में एक से अधिक दिखाया गया मोडहीन रूपों ज्यादातर मामलों में एक अच्छा उपयोगकर्ता अनुभव प्रदान नहीं करता है, और प्रपत्र जीवन प्रबंधन समस्याग्रस्त किया जा सकता है अगर रूपों को एक दूसरे पर निर्भर हैं।

+0

शायद मुझे फॉर्म जिम्मेदारियां गलत हैं, यह सोचकर कुछ केंद्रीय नियंत्रक होना चाहिए। इसके बजाय, उन्हें खुद का प्रबंधन करना चाहिए? मैं प्रतिबिंब के माध्यम से, सभी फॉर्म वर्गों की खोज करने और उन्हें टाइपमेप शब्दकोश में जोड़ने और गेट() या कुछ कॉल करने के बारे में सोच रहा था।रखरखाव की समस्या जिसे मैं हल करने की कोशिश कर रहा हूं वह स्पेगेटी फॉर्म कोड लिख रहा है, जिसमें मुझे कक्षा से कक्षा में बसने के लिए याद रखना है कि कौन सा फॉर्म किस रूप में खुलता है। – Jason

+0

@Jason संपादित उत्तर – ken2k

+0

ध्यान दें कि WinForms के पास फॉर्म प्रबंधन की सामान्य समस्या के लिए अंतर्निहित बेस क्लास है: ['ApplicationContext'] (https://msdn.microsoft.com/en-us/library/system.windows .forms.applicationcontext (v = vs.110) .aspx) –

3

मैं इस चाल का उपयोग करें, का कहना है कि Form1 मुख्य रूप है करते हैं:

private void button1_Click(object sender, EventArgs e) 
{ 
    LoadForm(new Form2()); 
} 

private void LoadForm(Form frm) 
{ 
    frm.FormClosed += new FormClosedEventHandler(frm_FormClosed); 
    this.Hide(); 
    // Here you can set a bunch of properties, apply skins, save logs... 
    // before you show any form 
    frm.Show(); 
} 

void frm_FormClosed(object sender, FormClosedEventArgs e) 
{ 
    this.Show(); 
} 
इसलिए जब आप किसी भी रूप से बंद कर दिया (Form1 को छोड़कर)

, Form1 पुन: दिखाई देगा फिर

अद्यतन

using (Form2 frm = new Form2()) 
{ 
    if (frm.ShowDialog() = DialogResult.ok) 
    { 
     //Do some things... 
    } 
} 

उन मामलों में पिछले फॉर्म को छिपाने की कोई आवश्यकता नहीं है

+0

हम्म, यह बनाए रखना थोड़ा मुश्किल लगता है, खासकर 5 रूपों के साथ प्रत्येक एक-दूसरे के विभिन्न रूपों को बुलाता है। – Jason

+0

नहीं, अन्य सभी रूपों में ऐसा करने की कोई ज़रूरत नहीं है, अन्य रूप संदेश, संवाद, डेटा को मुख्य रूप से भेज सकता है जो सही रूप से लोड करने के लिए संभाल सकता है, जब तक कि "शोडियलॉग" न हो: अपडेट –

+0

मुझे समझ में नहीं आता कि आपका क्या मतलब है। ऐसा लगता है जैसे आपका कोड फॉर्म 2, फॉर्म 3, या जो भी फॉर्म बंद हो जाता है, छुपा फॉर्म 1 फिर से खोलता है। लेकिन यह सीमित है। फॉर्म 1 को फॉर्म 5 खोलने की आवश्यकता हो सकती है। फॉर्म 5 को फॉर्म 3 खोलने की आवश्यकता हो सकती है। फॉर्म 3 को फॉर्म 7 खोलने की आवश्यकता हो सकती है। मुझे विश्वास नहीं है कि आपका समाधान बहुत एक्स्टेंसिबल है। – Jason

1

आपके आवेदन के आकार के आधार पर, आईडी का कहना है कि माइक्रोसॉफ़्ट एंटरप्राइज़ लाइब्रेरी और विशेष रूप से सीएबी ब्लॉक पर एक नज़र डालें।

इससे आपको अच्छी शुरुआत मिलनी चाहिए।

6

सबसे सरल परिदृश्य के अलावा किसी अन्य चीज में - आवेदन के जीवनकाल के लिए चलने वाला एक मुख्य मुख्य रूप, अल्पकालिक बाल रूपों के साथ - ApplicationContext से प्राप्त होने वाली कक्षा बनाने की अनुशंसा की जाती है।FormManager के स्थिर उदाहरण का उपयोग कर सकते

class FormManager : ApplicationContext { 
    //When each form closes, close the application if no other open forms 
    private void onFormClosed(object sender, EventArgs e) { 
     if (Application.OpenForms.Count == 0) { 
      ExitThread(); 
     } 
    } 

    //Any form which might be the last open form in the application should be created with this 
    public T CreateForm<T>() where T : Form, new() { 
     var ret = new T(); 
     ret.FormClosed += onFormClosed; 
     return ret; 
    } 

    //I'm using Lazy here, because an exception is thrown if any Forms have been 
    //created before calling Application.SetCompatibleTextRenderingDefault(false) 
    //in the Program class 
    private static Lazy<FormManager> _current = new Lazy<FormManager>(); 
    public static FormManager Current => _current.Value; 

    //Startup forms should be created and shown in the constructor 
    public FormManager() { 
     var f1 = CreateForm<Form1>(); 
     f1.Show(); 
     var f2 = CreateForm<Form2>(); 
     f2.ShowDialog(); 
    } 
} 

और Program.cs में Application.Run:: यह है कि जटिल नहीं है

static class Program { 
    /// <summary> 
    /// The main entry point for the application. 
    /// </summary> 
    [STAThread] 
    static void Main() { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 
     Application.Run(FormManager.Current); 
    } 
} 

आवेदन के जीवनकाल के दौरान, नए रूपों CreateForm के माध्यम से बनाया जाना चाहिए विधि FormClosed ईवेंट के साथ पंजीकृत करने के लिए:

var f3 = FormManager.Current.CreateForm<Form3>(); 
f3.Show(); 
var f4 = FormManager.Current.CreateForm<Form4>(); 
f4.ShowDialog(); 

आप FormManager.CreateForm के लिए कॉल से अधिक new Form3(); चाहें, तो आप FormManager पर एक RegisterForm विधि बना सकते हैं:

public void RegisterForm(Form frm) { 
    frm.FormClosed += onFormClosed; 
} 

और प्रत्येक नए Form पर RegisterForm फोन:

var f3 = new Form3(); 
FormManager.Current.RegisterForm(f3); 
var f4 = new Form4(); 
FormManager.Current.RegisterForm(f4); 

(एनबी। अपने सभी रूपों कुछ आधार वर्ग से विरासत है, तो बजाय मैन्युअल रूप से बुला प्रत्येक नए उदाहरण के लिए RegisterForm, आप इसे आधार वर्ग निर्माता में कह सकते हैं।)


ध्यान दें कि Application.OpenForms केवल उन रूपों है कि वर्तमान में दिखाई दे रहे हैं रिटर्न । यदि आवेदन तब तक बाहर नहीं निकलना चाहिए जब तक कि अभी भी छिपे हुए फॉर्म खुले हैं, तो FormManager को सभी रूपों का ट्रैक रखने के लिए कुछ संग्रह का उपयोग करना होगा। वह संग्रह निर्धारित करेगा कि आवेदन छोड़ना है या नहीं।

class FormManager : ApplicationContext { 
    private List<Form> forms = new List<Form>(); 

    private void onFormClosed(object sender, EventArgs e) { 
     forms.Remove((Form)sender); 
     if (!forms.Any()) { 
      ExitThread(); 
     } 
    } 

    public void RegisterForm(Form frm) { 
     frm.FormClosed += onFormClosed; 
     forms.Add(frm); 
    } 

    public T CreateForm<T>() where T : Form, new() { 
     var ret = new T(); 
     RegisterForm(ret); 
     return ret; 
    } 

    private static Lazy<FormManager> _current = new Lazy<FormManager>(); 
    public static FormManager Current => _current.Value; 
} 
+0

इस बारे में बिल्कुल नहीं पता था, धन्यवाद! – Jason

+1

@ जेसन मैंने अपने उत्तर पर विस्तार किया है। –

0
public partial class Form1 : Form 
{ 
    private static Form1 inst; 
    public static Form1 GetForm 
    { 
     get 
     { 
      if (inst == null || inst.IsDisposed) 
      { 
       inst = new Form1(); 
      } 
      return inst; 
     } 
    } 
    public Form1() 
    { 
     InitializeComponent(); 
     inst = this; 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     Form2.GetForm.Show(); 
     this.Hide(); 
    } 
} 

public partial class Form2 : Form 
{ 
    private static Form2 inst; 
    public static Form2 GetForm 
    { 
     get 
     { 
      if (inst == null || inst.IsDisposed) 
       inst = new Form2(); 
      return inst; 
     } 
    } 
    public Form2() 
    { 
     InitializeComponent(); 
    } 
    private void button1_Click(object sender, EventArgs e) 
    { 
     Form1.GetForm.Show(); 
     this.Hide(); 
    } 
    private void Form2_FormClosed(object sender, FormClosedEventArgs e) 
    { 
     Form1.GetForm.Show(); 
    } 
} 

अगर आप दो से अधिक फार्म तो के रूप में From2

+0

इस मुद्दे के जवाब के साथ कुछ स्पष्टीकरण जोड़ें कि इस मुद्दे को वर्तमान समस्या को ठीक करने में ओपी की मदद कैसे करें –

संबंधित मुद्दे