क्या GUI को डिजाइन और कार्यान्वित करने के लिए किसी प्रकार की व्यवस्थित रणनीति है?


18

मैं C # में GUI एप्लिकेशन बनाने के लिए Visual Studio का उपयोग कर रहा हूं। टूलबॉक्स एक निफ्टी घटक पैलेट के रूप में कार्य करता है जो मुझे बटन और अन्य तत्वों को आसानी से खींचने और छोड़ने की अनुमति देता है (स्पष्टता के लिए जब भी मैं अपने नियंत्रण पर "नियंत्रण" का अर्थ बटन कहूंगा), जो स्थिर रूपों को करना काफी आसान बनाता है। हालाँकि, मैं दो समस्याओं में भाग लेता हूँ:

  • पहली जगह में बटन बनाना बहुत काम का है। जब मेरे पास एक फॉर्म होता है जो स्थिर नहीं होता है (यानी बटन या अन्य नियंत्रण उपयोगकर्ता द्वारा किए गए अनुसार रन टाइम पर बनाए जाते हैं) मैं पैलेट का उपयोग बिल्कुल नहीं कर सकता। इसके बजाय मुझे प्रत्येक बटन को मैन्युअल रूप से बनाना होगा, जो भी विधि मैं उपयोग कर रहा हूं, उसमें कंस्ट्रक्टर को कॉल करके, और फिर मैन्युअल रूप से बटन की ऊंचाई, चौड़ाई, स्थिति, लेबल, ईवेंट हैंडलर और इसी तरह निर्दिष्ट करके प्रारंभ करें। यह बेहद थकाऊ है क्योंकि मुझे इन सभी कॉस्मेटिक मापदंडों पर अनुमान लगाने की आवश्यकता है कि यह देखने में सक्षम नहीं है कि फॉर्म कैसा दिखेगा, और यह प्रत्येक बटन के लिए दोहराए गए कोड की कई लाइनें भी उत्पन्न करता है।
  • बटनों को कुछ करना भी बहुत काम है। पूर्ण विशेषताओं वाले एप्लिकेशन में घटनाओं से निपटना एक बहुत बड़ा दर्द है। एकमात्र तरीका मुझे पता है कि यह कैसे करना है एक बटन का चयन करना है, इसके गुणों में ईवेंट टैब पर जाएं, OnClickईवेंट पर क्लिक करें ताकि यह ईवेंट के Formकोड में उत्पन्न हो , फिर ईवेंट के बॉडी में भरें। चूंकि मैं तर्क और प्रस्तुति को अलग करना चाहता हूं, इसलिए मेरे सभी इवेंट हैंडलर उपयुक्त व्यावसायिक लॉजिक फ़ंक्शन के लिए सिंगल-लाइन कॉल करते हैं। लेकिन कई बटन के लिए इसका उपयोग करना (उदाहरण के लिए, एमएस वर्ड जैसे एप्लिकेशन में मौजूद बटनों की संख्या की कल्पना करना) Formदर्जनों बॉयलरप्लेट ईवेंट हैंडलर विधियों के साथ मेरे कोड को प्रदूषित करता है और इसे बनाए रखना मुश्किल है।

इनकी वजह से, हैलो वर्ल्ड की तुलना में कोई भी GUI प्रोग्राम वास्तव में मेरे लिए बहुत अव्यवहारिक है। स्पष्ट होने के लिए, मुझे कोई समस्या नहीं है कि मैं उन कार्यक्रमों में जटिलता से निपटता हूं जो मैं लिखता हूं जिनमें न्यूनतम यूआई है - मुझे ऐसा लगता है कि मैं अपने व्यावसायिक तर्क कोड को बड़े पैमाने पर क्षमता के साथ ओओपी का उपयोग करने में सक्षम हूं। लेकिन जीयूआई विकसित करते समय, मैं फंस गया हूं। यह इतना थकाऊ लगता है कि मुझे लगता है कि मैं पहिया को फिर से मजबूत कर रहा हूं, और कहीं न कहीं एक किताब है जो बता रही है कि कैसे जीयूआई ठीक से करना है जो मैंने पढ़ा नहीं है।

क्या मैं कुछ भूल रहा हूँ? या क्या सभी C # डेवलपर्स सिर्फ दोहराव वाले इवेंट हैंडलर और बटन निर्माण कोड की अंतहीन सूचियों को स्वीकार करते हैं?


एक (उम्मीद के मुताबिक मददगार) संकेत के रूप में, मुझे उम्मीद है कि एक अच्छा जवाब के बारे में बात करेंगे:

  • बार-बार बटन निर्माण को आसान बनाने के लिए OOP तकनीकों (जैसे फ़ैक्टरी पैटर्न) का उपयोग करना
  • कई ईवेंट हैंडलर्स को एक एकल विधि में संयोजित Senderकरना जो यह पता लगाने के लिए जांचता है कि किस बटन ने इसे कॉल किया है, और तदनुसार व्यवहार करता है
  • XAML और विंडोज फॉर्म के बजाय WPF का उपयोग करना

आपको इनमें से किसी का भी उल्लेख नहीं करना है। यह सिर्फ मेरा सबसे अच्छा अनुमान है कि मैं किस तरह के उत्तर की तलाश कर रहा हूं।


जैसा कि मैं देख रहा हूँ कि हाँ फैक्ट्री एक अच्छा पैटर्न होगा, लेकिन मुझे बहुत अधिक मॉडल-व्यू-कंट्रोलर पैटर्न दिखाई देता है, जिसमें कमांड्स सीधे घटनाओं के बजाय नियंत्रित होते हैं। WPF आमतौर पर MVVM है लेकिन MVC अच्छी तरह से संभव है। वर्तमान में हमारे पास 90% पर MVC का उपयोग करके WPF में एक विशाल सॉफ़्टवेयर है। सभी आदेशों को नियंत्रक को भेज दिया जाता है और वह हमेशा के लिए संभाल लेते हैं
फ्रेंक

क्या आप GUI संपादक के साथ सभी संभव बटन के साथ गतिशील रूप नहीं बना सकते हैं, और बस उन चीजों को बनाते हैं जिन्हें आपको गतिशील रूप से अदृश्य की आवश्यकता नहीं है? बहुत कम काम की तरह लगता है।
हंस-पीटर स्टॉर्र

@hstoerr लेकिन लेआउट को काम में लाना कठिन होगा। बहुत सारे बटन ओवरलैप होंगे।
सुपरस्टार

जवाबों:


22

आपके द्वारा बताए गए इन मुद्दों से निपटने के लिए कई कार्यप्रणाली वर्षों से विकसित हुई हैं, जो हैं, मैं मानता हूं, दो मुख्य मुद्दे जिन्हें यूआई फ्रेमवर्क ने हाल के वर्षों में संबोधित किया है। एक WPF पृष्ठभूमि से आ रहा है, ये इस प्रकार हैं:

अनिवार्य डिजाइन, बल्कि अनिवार्य है

जब आप तात्कालिक नियंत्रणों और उनके गुणों को सेट करने के लिए श्रमसाध्य लेखन कोड का वर्णन करते हैं, तो आप UI डिज़ाइन के अनिवार्य मॉडल का वर्णन कर रहे हैं। WinForms डिज़ाइनर के साथ भी, आप बस उस मॉडल पर एक आवरण का उपयोग कर रहे हैं - Form1.Designer.cs फ़ाइल खोलें और आपको वह सब कोड वहां दिखाई दे रहा है।

WPF और XAML के साथ - और इसी तरह के अन्य मॉडलों में, निश्चित रूप से, HTML के बाद से - आपको अपने लेआउट का वर्णन करने की उम्मीद है, और फ्रेमवर्क को लागू करने की भारी उठाने की अनुमति दें। UI तत्वों के बीच संबंध का वर्णन करने के लिए आप पैनेल्स (ग्रिड, या वेपरपैनल, आदि) जैसे होशियार नियंत्रणों का उपयोग करते हैं, लेकिन उम्मीद यह है कि आप मैन्युअल रूप से उन्हें स्थान नहीं देते। दोहराए जाने योग्य नियंत्रण जैसे कि एएसपी.नेट रिपीटर या डब्ल्यूपीएफ के आइटमकंट्रोल जैसी लचीली अवधारणाएं - आप दोहराए गए कोड को लिखे बिना डायनेमिक स्केलिंग यूआई बनाने में मदद करते हैं, जिससे डायनेमिक रूप से बढ़ते डेटा एंटिटीज को डायनामिक रूप से कंट्रोल के रूप में प्रतिनिधित्व किया जा सकता है।

WPF के DataTemplates आपको परिभाषित करने की अनुमति देते हैं - फिर से, घोषित रूप से - यूआई अच्छाई के छोटे सोने की डली और उन्हें आपके डेटा से मेल खाते हैं; उदाहरण के लिए, ग्राहक डेटा ऑब्जेक्ट्स की एक सूची एक ItemControl के लिए बाध्य हो सकती है, और एक अलग डेटा टेम्प्लेट इस पर निर्भर करता है कि क्या वह एक नियमित कर्मचारी है (नाम और पते के साथ एक मानक ग्रिड पंक्ति टेम्पलेट का उपयोग करें) या एक मुख्य ग्राहक, जबकि एक अलग टेम्पलेट , एक तस्वीर के साथ और आसान करने के लिए पहुँच बटन प्रदर्शित कर रहे हैं। फिर, में कोड लिखे बिना विशिष्ट विंडो , बस होशियार नियंत्रण जो उनके डेटा-संदर्भ के बारे में जानते हैं, और इस प्रकार आप उन्हें केवल अपने डेटा से बाँध सकते हैं और उन्हें प्रासंगिक संचालन करने दे सकते हैं।

डेटा बाइंडिंग और कमांड पृथक्करण

डेटा बाइंडिंग पर टच करते हुए, WPF के डेटाबाइंडिंग (और, फिर से, अन्य रूपरेखाओं में, AngularJS की तरह) आपको डेटा यूनिट (कहो, ग्राहक का नाम) और नियंत्रण (लिंक, एक टेक्स्टबॉक्स) के साथ अपने इरादे को बताने की अनुमति देता है। ढांचा पाइपलाइन को संभालता है। लॉजिक को इसी तरह से हैंडल किया जाता है। कंट्रोलर-आधारित व्यावसायिक-तर्क के लिए कोड-बैक इवेंट-हैंडलर को मैन्युअल रूप से वायर करने के बजाय, आप नियंत्रक ऑब्जेक्ट के नियंत्रक के व्यवहार (जैसे, एक बटन के कमांड प्रॉपर्टी) को एक कमांड ऑब्जेक्ट से लिंक करने के लिए डेटा बाइंडिंग तंत्र का उपयोग करते हैं जो गतिविधि की डली का प्रतिनिधित्व करता है।

यह इस आदेश को हर बार घटना संचालकों को फिर से लिखने के बिना खिड़कियों के बीच साझा करने की अनुमति देता है।

एब्सट्रैक्शन का उच्च स्तर

आपकी दो समस्याओं के लिए ये दोनों समाधान विंडोज फॉर्म के घटना-संचालित प्रतिमान की तुलना में उच्च स्तर पर अमूर्तता के लिए एक चाल का प्रतिनिधित्व करते हैं जो आपको सही रूप से थकाऊ लगता है।

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

MVVM पैटर्न इस प्रतिमान के लिए माइक्रोसॉफ्ट के दृष्टिकोण है। मैं उस पर पढ़ने का सुझाव देता हूं।

यह एक मोटा उदाहरण है कि यह मॉडल कैसा दिखेगा और यह आपके समय और कोड की लाइनों को कैसे बचाएगा। यह संकलन नहीं करेगा, लेकिन यह छद्म WPF है। :)

कहीं आपके अनुप्रयोग संसाधनों में, आप डेटा टेम्पलेट परिभाषित करते हैं:

<DataTemplate x:DataType="Customer">
   <TextBox Text="{Binding Name}"/> 
</DataTemplate>

<DataTemplate x:DataType="PrimeCustomer">
   <Image Source="GoldStar.png"/>
   <TextBox Text="{Binding Name}"/> 
</DataTemplate>

अब, आप अपनी मुख्य स्क्रीन को एक ViewModel से लिंक करते हैं, एक वर्ग जो आपके डेटा को उजागर करता है। कहो, ग्राहकों का एक संग्रह (बस List<Customer>) और एक कमांड ऑब्जेक्ट (फिर से, एक साधारण सार्वजनिक संपत्ति का प्रकार ICommand)। यह लिंक बाध्यकारी की अनुमति देता है:

public class CustomersnViewModel
{
     public List<Customer> Customers {get;}
     public ICommand RefreshCustomerListCommand {get;}  
}

और UI:

<ListBox ItemsSource="{Binding Customers}"/>
<Button Command="{Binding RefreshCustomerListCommand}">Refresh</Button>

और बस। ListBox के सिंटैक्स, ViewModel के ग्राहकों की सूची को हड़प लेंगे और उन्हें UI पर रेंडर करने का प्रयास करेंगे। पहले से परिभाषित दो डेटाटेम्पलेट्स के कारण, यह संबंधित टेम्प्लेट को आयात करेगा (डेटाटाइप के आधार पर, ग्राहक से विरासत में मिला कस्टमर) और इसे लिस्टबॉक्स की सामग्री के रूप में रखा। कोई लूपिंग, कोड के माध्यम से नियंत्रण की कोई गतिशील पीढ़ी नहीं।

बटन, इसी तरह, अपने व्यवहार को ICommand कार्यान्वयन से जोड़ने के लिए वाक्यविन्यास है, जो संभवतः Customersसंपत्ति को अद्यतन करने के लिए जानता है - स्वचालित रूप से UI को अपडेट करने के लिए डेटा-बाइंडिंग ढांचे को संकेत देना।

मैंने यहाँ कुछ शॉर्टकट लिए हैं, बेशक, लेकिन यह इसका सार है।


5

सबसे पहले, मैं इस लेख श्रृंखला की सिफारिश करता हूं: http://codebetter.com/jeremymiller/2007/07/26/the-build-your-own-cab-series-table-of-contents/ - यह विवरण की समस्याओं को संबोधित नहीं करता है आपके बटन कोड के साथ, लेकिन यह आपको विशेष रूप से GUI अनुप्रयोगों के लिए अपने स्वयं के एप्लिकेशन फ्रेमवर्क को डिजाइन और कार्यान्वित करने के लिए एक व्यवस्थित रणनीति देता है, जो आपको दिखाता है कि अपने विशिष्ट फॉर्म एप्लिकेशन को MVC, MVP, MVVM कैसे लागू करें।

"घटनाओं से निपटने" के बारे में अपने प्रश्न को संबोधित करते हुए: यदि आपके पास एक समान तरीके से काम करने वाले बटनों के साथ बहुत सारे रूप हैं, तो यह संभवतः आपके द्वारा अपने "एप्लिकेशन फ्रेमवर्क" में इवेंट हैंडलर असाइनमेंट को लागू करने के लिए भुगतान करेगा। GUI डिज़ाइनर का उपयोग करके क्लिक ईवेंट्स असाइन करने के बजाय, एक नामकरण परंपरा बनाएं कि किसी विशिष्ट नाम के बटन के लिए "क्लिक" हैंडलर का नाम कैसे रखा जाए। उदाहरण के लिए - बटन MyNiftyButton_ClickHandlerके लिए बटन के लिए MyNiftyButton। फिर एक पुन: प्रयोज्य दिनचर्या (प्रतिबिंब का उपयोग करना) लिखना मुश्किल नहीं है, जो किसी प्रपत्र के सभी बटन पर पुनरावृत्त करता है, जांचें कि क्या प्रपत्र में संबंधित क्लिक हैंडलर है और हैंडलर को स्वचालित रूप से ईवेंट को असाइन करें। एक उदाहरण के लिए यहाँ देखें ।

और अगर आप केवल बटनों के एक समूह के लिए केवल एक घटना हैंडलर का उपयोग करना चाहते हैं, तो यह भी संभव होगा। चूंकि प्रत्येक ईवेंट हैंडलर प्रेषक को पास कर देता है, और प्रेषक हमेशा वह बटन होता है जिसे दबाया गया था, आप प्रत्येक बटन की "नाम" संपत्ति का उपयोग करके व्यवसाय कोड को भेज सकते हैं।

बटनों (या अन्य नियंत्रणों) के गतिशील निर्माण के लिए: आप किसी टेम्पलेट को देखने के उद्देश्य से बिना उपयोग किए गए फॉर्म पर डिजाइनर के साथ बटन या अन्य नियंत्रण बना सकते हैं । फिर, आप टेम्पलेट नियंत्रण को क्लोन करने और स्थान या आकार जैसे गुणों को बदलने के लिए प्रतिबिंब ( उदाहरण के लिए यहां देखें ) का उपयोग करते हैं। कोड में मैन्युअल रूप से दो या तीन दर्जन संपत्तियों को शुरू करने की तुलना में यह बहुत सरल होगा।

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


WPF में करना संभव है और यह बहुत आसान है। आप बस आदेशों की एक सूची भरते हैं (विशिष्ट कोडित पूर्व कार्य) और अपनी खिड़की पर स्रोत सेट करें। आप एक अच्छा सरल विज़ुअल टेम्प्लेट बनाते हैं और आपको ध्यान रखने की ज़रूरत है कि आप जो कमांड चाहते हैं उसके साथ एक संग्रह भर रहे हैं और महान WPF बाइंडिंग आपके लिए बाकी का ध्यान रखते हैं।
फ्रेंक
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.