WinForms में मॉडल-व्यू-प्रस्तुतकर्ता


90

मैं WinForms का उपयोग करते हुए पहली बार MVP विधि को लागू करने की कोशिश कर रहा हूं।

मैं प्रत्येक परत के कार्य को समझने की कोशिश कर रहा हूं।

मेरे कार्यक्रम में मेरे पास एक GUI बटन है, जिस पर क्लिक करने पर एक ओपनफ़ेडियलॉग विंडो खुलती है।

तो एमवीपी का उपयोग करते हुए, जीयूआई बटन क्लिक इवेंट को संभालता है और फिर प्रस्तोता को फोन करता है।

Presenter.openfile () के भीतर, फिर उस फ़ाइल को मॉडल लेयर में खोलने के लिए प्रतिनिधि करना चाहिए, या जैसा कि प्रक्रिया के लिए कोई डेटा या तर्क नहीं है, क्या यह केवल अनुरोध पर कार्य करना चाहिए और ओपनफेडियलॉग विंडो खोलें?

अद्यतन: मैंने एक इनाम देने का फैसला किया है क्योंकि मुझे लगता है कि मुझे इस पर और सहायता की आवश्यकता है, और अधिमानतः नीचे मेरे विशिष्ट बिंदुओं के अनुरूप है, ताकि मेरे पास संदर्भ हो।

ठीक है, एमवीपी पर पढ़ने के बाद, मैंने पैसिव व्यू को लागू करने का फैसला किया है। प्रभावी रूप से मेरे पास एक Winform पर नियंत्रण का एक गुच्छा होगा जिसे एक प्रस्तुतकर्ता द्वारा नियंत्रित किया जाएगा और फिर मॉडल (नों) को सौंपे गए कार्य। मेरे विशिष्ट बिंदु नीचे हैं:

  1. जब winform लोड होता है, तो उसे ट्रीव्यू प्राप्त करना होता है। क्या मैं यह सोचने में सही हूं कि दृश्य को इसलिए एक विधि को कॉल करना चाहिए जैसे: प्रस्तुतकर्ता.गेट्री (), यह बदले में मॉडल को सौंप देगा, जो ट्रीव्यू के लिए डेटा प्राप्त करेगा, इसे बनाएं और इसे कॉन्फ़िगर करें, इसे वापस लौटाएं। प्रस्तुतकर्ता, जो बदले में उस दृश्य को पारित करेगा, जो बाद में इसे एक पैनल को कहेगा;

  2. क्या यह Winform पर किसी भी डेटा नियंत्रण के लिए समान होगा, क्योंकि मेरे पास एक डेटाग्रिडव्यू भी है?

  3. माय ऐप, एक ही विधानसभा के साथ कई मॉडल कक्षाएं हैं। यह प्लगइन्स के साथ एक प्लगइन आर्किटेक्चर का भी समर्थन करता है जिसे स्टार्टअप पर लोड करने की आवश्यकता होती है। क्या दृश्य बस एक प्रस्तोता विधि को कॉल करेगा, जो बदले में एक विधि को कॉल करेगा जो प्लगइन्स को लोड करता है और दृश्य में जानकारी प्रदर्शित करता है? फिर कौन सा टियर प्लगइन संदर्भों को नियंत्रित करेगा। क्या दृश्य उनके या प्रस्तुतकर्ता के संदर्भ में होगा?

  4. क्या मैं यह सोचने में सही हूं कि दृश्य को प्रस्तुति के बारे में हर एक चीज को ट्रीव्यू नोड रंग से, डेटाग्रिड आकार, आदि से संभालना चाहिए?

मुझे लगता है कि वे मेरी मुख्य चिंताएं हैं और अगर मुझे समझ में आता है कि प्रवाह कैसा होना चाहिए तो मुझे लगता है कि मैं ठीक हो जाऊंगा।


यह लिंक खो दिया गया है। http://www.derekgreer/2008/11/23/… एमवीपी की कुछ शैलियों की व्याख्या करता है। यह जोहान के शानदार जवाब के अलावा मददगार साबित हो सकता है।
ak3nat0n

जवाबों:


123

यह एमवीपी और आपके विशिष्ट मुद्दों पर मेरी विनम्रता है।

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

दूसरा , एक दृश्य हमेशा एक प्रस्तुतकर्ता द्वारा नियंत्रित किया जाता है । इस तरह के एक प्रस्तुतकर्ता के कानून, व्यवहार और विशेषताओं को एक इंटरफेस द्वारा भी वर्णित किया गया है । जब तक वह अपने दृश्य इंटरफ़ेस के नियमों का पालन करता है, तब तक उस इंटरफ़ेस को ठोस दृश्य कार्यान्वयन में कोई रुचि नहीं है।

तीसरा , चूंकि एक प्रस्तुतकर्ता अपने दृष्टिकोण को नियंत्रित करता है, इसलिए निर्भरता को कम करने के लिए वास्तव में इसके प्रस्तुतकर्ता के बारे में कुछ भी जानने के दृश्य होने में कोई लाभ नहीं है। प्रस्तुतकर्ता और दृश्य के बीच एक सहमति अनुबंध है और यह दृश्य इंटरफ़ेस द्वारा कहा गया है।

तीसरे के निहितार्थ हैं:

  • प्रस्तुतकर्ता के पास कोई भी तरीका नहीं है जिसे दृश्य कॉल कर सकता है, लेकिन दृश्य में ऐसी घटनाएं हैं जिन्हें प्रस्तुतकर्ता सदस्यता ले सकता है।
  • प्रस्तुतकर्ता इसका दृष्टिकोण जानता है। मैं कंक्रीट प्रस्तुतकर्ता पर निर्माता इंजेक्शन के साथ इसे पूरा करना पसंद करता हूं।
  • प्रस्तोता के पास इसे नियंत्रित करने के बारे में कोई विचार नहीं है; यह सिर्फ किसी भी प्रस्तुतकर्ता प्रदान नहीं किया जाएगा।

आपके मुद्दे के लिए, ऊपर कुछ हद तक सरलीकृत कोड में इस तरह दिख सकता है:

interface IConfigurationView
{
    event EventHandler SelectConfigurationFile;

    void SetConfigurationFile(string fullPath);
    void Show();
}

class ConfigurationView : IConfigurationView
{
    Form form;
    Button selectConfigurationFileButton;
    Label fullPathLabel;

    public event EventHandler SelectConfigurationFile;

    public ConfigurationView()
    {
        // UI initialization.

        this.selectConfigurationFileButton.Click += delegate
        {
            var Handler = this.SelectConfigurationFile;

            if (Handler != null)
            {
                Handler(this, EventArgs.Empty);
            }
        };
    }

    public void SetConfigurationFile(string fullPath)
    {
        this.fullPathLabel.Text = fullPath;
    }

    public void Show()
    {
        this.form.ShowDialog();        
    }
}

interface IConfigurationPresenter
{
    void ShowView();
}

class ConfigurationPresenter : IConfigurationPresenter
{
    Configuration configuration = new Configuration();
    IConfigurationView view;

    public ConfigurationPresenter(IConfigurationView view)
    {
        this.view = view;            
        this.view.SelectConfigurationFile += delegate
        {
            // The ISelectFilePresenter and ISelectFileView behaviors
            // are implicit here, but in a WinForms case, a call to
            // OpenFileDialog wouldn't be too far fetched...
            var selectFilePresenter = Gimme.The<ISelectFilePresenter>();
            selectFilePresenter.ShowView();
            this.configuration.FullPath = selectFilePresenter.FullPath;
            this.view.SetConfigurationFile(this.configuration.FullPath);
        };
    }

    public void ShowView()
    {
        this.view.SetConfigurationFile(this.configuration.FullPath);
        this.view.Show();
    }
}

उपरोक्त के अतिरिक्त, मेरे पास आमतौर पर एक आधार IViewइंटरफ़ेस होता है जहां मैं स्टैश करता हूंShow() और किसी भी मालिक के दृश्य या दृश्य शीर्षक को टकराता हूं जिससे मेरे विचार आमतौर पर लाभान्वित होते हैं।

आपके प्रश्नों के लिए:

1. जब विनफॉर्म लोड होता है, तो उसे ट्रीव्यू प्राप्त करना होता है। क्या मैं यह सोचने में सही हूं कि दृश्य को इसलिए एक विधि को कॉल करना चाहिए जैसे: प्रस्तुतकर्ता.गेट्री (), यह बदले में मॉडल को सौंप देगा, जो ट्रीव्यू के लिए डेटा प्राप्त करेगा, इसे बनाएं और इसे कॉन्फ़िगर करें, इसे वापस लौटाएं। प्रस्तुतकर्ता, जो बदले में उस दृश्य को पास करेगा जो तब इसे केवल एक पैनल को कहता है,

मैं कॉल करने IConfigurationView.SetTreeData(...)से IConfigurationPresenter.ShowView()ठीक पहले कॉल करूंगाIConfigurationView.Show()

2. क्या यह Winform पर किसी भी डेटा नियंत्रण के लिए समान होगा, क्योंकि मेरे पास एक डेटाग्रिडव्यू भी है?

हां, मैं उसके लिए कॉल करूंगा IConfigurationView.SetTableData(...)। यह दिए गए डेटा को प्रारूपित करने की दृष्टि पर निर्भर है। प्रस्तुतकर्ता बस दृश्य के अनुबंध का पालन करता है कि वह सारणीबद्ध डेटा चाहता है।

3. माय ऐप, एक ही विधानसभा के साथ कई मॉडल कक्षाएं हैं। यह प्लगइन्स के साथ एक प्लगइन आर्किटेक्चर का भी समर्थन करता है जिसे स्टार्टअप पर लोड करने की आवश्यकता होती है। क्या दृश्य बस एक प्रस्तोता विधि को कॉल करेगा, जो बदले में एक विधि को कॉल करेगा जो प्लगइन्स को लोड करता है और दृश्य में जानकारी प्रदर्शित करता है? फिर कौन सा टियर प्लगइन संदर्भों को नियंत्रित करेगा। क्या दृश्य उनके या प्रस्तुतकर्ता के संदर्भ में होगा?

यदि प्लगइन्स दृश्य-संबंधी हैं, तो विचारों को उनके बारे में जानना चाहिए, लेकिन प्रस्तुतकर्ता नहीं। यदि वे सभी डेटा और मॉडल के बारे में हैं, तो दृश्य को उनके साथ कुछ भी नहीं करना चाहिए।

4. क्या मैं यह सोचने में सही हूं कि दृश्य को प्रेजेंटेशन के बारे में हर एक चीज को ट्रीव्यू नोड कलर से, डेटाग्रिड के आकार, आदि से संभालना चाहिए?

हाँ। इसके बारे में सोचो कि प्रस्तुतकर्ता XML प्रदान करता है जो डेटा का वर्णन करता है और वह दृश्य जो डेटा लेता है और उस पर CSS स्टाइलशीट लागू होता है। ठोस शब्दों में, प्रस्तुतकर्ता कॉल कर सकता है IRoadMapView.SetRoadCondition(RoadCondition.Slippery)और दृश्य फिर सड़क को लाल रंग में प्रस्तुत करता है।

क्लिक किए गए नोड्स के डेटा के बारे में क्या?

5. यदि मैं ट्रिनोड्स पर क्लिक करता हूं, तो क्या मुझे प्रस्तुतकर्ता के लिए विशिष्ट नोड से गुजरना चाहिए और फिर उस से प्रस्तुतकर्ता काम करेगा कि उसे किस डेटा की आवश्यकता है और फिर उस डेटा के लिए मॉडल पूछता है, इसे दृश्य में वापस प्रस्तुत करने से पहले?

यदि संभव हो तो, मैं पेड़ को एक शॉट में एक दृश्य में प्रस्तुत करने के लिए आवश्यक सभी डेटा पास करूंगा। लेकिन अगर कुछ डेटा को शुरू से ही पास करने के लिए बहुत बड़ा है या अगर यह अपनी प्रकृति में गतिशील है और मॉडल (प्रस्तुतकर्ता के माध्यम से) से "नवीनतम स्नैपशॉट" की आवश्यकता है, तो मैं कुछ इस तरह जोड़ूंगा जैसे event LoadNodeDetailsEventHandler LoadNodeDetailsकि इंटरफ़ेस। प्रस्तुतकर्ता इसे सदस्यता ले सकता है, LoadNodeDetailsEventArgs.Nodeमॉडल से नोड का विवरण (संभवत: अपनी आईडी के माध्यम से किसी प्रकार का) प्राप्त कर सकता है, ताकि घटना हैंडलर प्रतिनिधि के वापस आने पर दृश्य इसके दिखाए गए नोड विवरण को अपडेट कर सके। ध्यान दें कि यदि उपयोगकर्ता को अच्छे उपयोगकर्ता अनुभव के लिए डेटा धीमा हो सकता है, तो इसके लिए async पैटर्न की आवश्यकता हो सकती है।


3
मुझे नहीं लगता कि आपको आवश्यक रूप से दृश्य और प्रस्तुतकर्ता को डिकूप करना होगा। मैं आमतौर पर मॉडल और प्रस्तुतकर्ता को डिकूप करता हूं, प्रस्तुतकर्ता को मॉडल की घटनाओं को सुनने और तदनुसार कार्य करता है (दृश्य को अपडेट करें)। दृश्य में प्रस्तुतकर्ता होने से दृश्य और प्रस्तुतकर्ता के बीच संचार कम हो जाता है।
कास्परज

11
@ एलजॉन: आप कहते हैं कि दृश्य में एक प्रस्तुतकर्ता होने से दृश्य और प्रस्तुतकर्ता के बीच संचार कम हो जाता है , लेकिन मैं दृढ़ता से असहमत हूं । मेरा दृष्टिकोण यह है: जब दृश्य प्रस्तुतकर्ता के बारे में जानता है, तो प्रत्येक दृश्य घटना के लिए दृश्य को यह तय करना होगा कि कॉल करने के लिए कौन सा प्रस्तुतकर्ता विधि उचित है। यह "जटिलता के 2 अंक" है, क्योंकि दृश्य वास्तव में नहीं जानता कि कौन सा दृश्य घटना है जो कि प्रस्तुतकर्ता विधि से मेल खाती है । अनुबंध यह निर्दिष्ट नहीं करता है।
जोहान जेरेल

5
@ एलजॉन: यदि, दूसरी ओर, दृश्य केवल वास्तविक घटना को उजागर करता है, तो प्रस्तुतकर्ता खुद (जो जानता है कि जब कोई दृश्य घटना होती है तो वह क्या करना चाहता है) सिर्फ सही काम करने के लिए उसकी सदस्यता लेता है। यह केवल "जटिलता का 1 बिंदु" है, जो मेरी पुस्तक में "जटिलता के 2 अंक" से दोगुना है। सामान्यतया, कम युग्मन का अर्थ है किसी परियोजना के चलाने पर कम रखरखाव लागत।
जोहान जेरेल

9
मैं भी इस लिंक में बताए गए एन्कैप्सुलेटेड प्रस्तोता का उपयोग करने की प्रवृत्ति रखता हूं । इस लिंक में बताया गया है ।derekgreer/2008/11/23/… जिसमें दृश्य प्रस्तोता का एकमात्र धारक है।
ak3nat0n

3
@ ak3nat0n: एमवीपी की तीन शैलियों के संबंध में आपके द्वारा दिए गए लिंक में बताया गया है, मेरा मानना ​​है कि जोहान के इस उत्तर को तीसरी शैली के साथ सबसे अधिक निकटता से जोड़ा जा सकता है जिसे ऑब्जर्विंग प्रस्तोता स्टाइल का नाम दिया गया है : "
डेविड आरआर

11

प्रस्तुतकर्ता, जिसमें दृश्य में सभी तर्क हैं, बटन पर क्लिक किया जाना चाहिए जैसा कि @JochemKempe कहता है । व्यावहारिक रूप में, बटन ईवेंट हैंडलर कॉल पर क्लिक करता है presenter.OpenFile()। प्रस्तुतकर्ता तब यह निर्धारित करने में सक्षम है कि क्या किया जाना चाहिए।

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

चयनित फ़ाइल को फिर प्रस्तुतकर्ता को लौटा दिया जाएगा जो अपना तर्क जारी रखे हुए है। इसमें फ़ाइल को संसाधित करने के लिए जो भी मॉडल या सेवा शामिल होनी चाहिए वह शामिल है।

एमवीपी पैटर्न का उपयोग करने का प्राथमिक कारण, इमो यूआई तकनीक को व्यू लॉजिक से अलग करना है। इस प्रकार प्रस्तुतकर्ता सभी लॉजिक को ऑर्केस्ट्रा करता है जबकि दृश्य इसे यूआई लॉजिक से अलग रखता है। प्रस्तुतकर्ता को पूरी तरह से परीक्षण योग्य बनाने का यह बहुत अच्छा दुष्प्रभाव है।

अद्यतन: चूंकि प्रस्तुतकर्ता एक विशिष्ट दृश्य में पाए जाने वाले तर्क का अवतार है , दृश्य-प्रस्तुतकर्ता संबंध IMO एक-से-एक संबंध है। और सभी व्यावहारिक उद्देश्यों के लिए, एक दृश्य उदाहरण (कहते हैं एक प्रपत्र) एक प्रस्तुतकर्ता उदाहरण के साथ बातचीत करता है, और एक प्रस्तुतकर्ता उदाहरण केवल एक दृश्य उदाहरण के साथ बातचीत करता है।

WinForms के साथ MVP के मेरे कार्यान्वयन में, प्रस्तुतकर्ता हमेशा दृश्य की UI क्षमताओं का प्रतिनिधित्व करने वाले इंटरफ़ेस के माध्यम से दृश्य के साथ सहभागिता करता है। इस इंटरफ़ेस को किस दृष्टिकोण से लागू किया जाता है, इस पर कोई सीमा नहीं है, इस प्रकार विभिन्न "विजेट" एक ही दृश्य इंटरफ़ेस को लागू कर सकते हैं और प्रस्तुतकर्ता वर्ग का पुन: उपयोग कर सकते हैं।


धन्यवाद। तो प्रस्तुतकर्ता में। OpenFile () विधि में, यह ओफ़्फ़ेडियल डायलॉग दिखाने के लिए कोड नहीं होना चाहिए? इसके बजाय इसे उस विंडो को दिखाने के लिए वापस जाना चाहिए?
डैरेन यंग

4
सही है, मैं प्रस्तुतकर्ता को सीधे संवाद बॉक्स खोलने की अनुमति नहीं दूंगा, क्योंकि यह आपके परीक्षणों को तोड़ देगा। या तो देखने के लिए या, जैसा कि मैंने कुछ परिदृश्यों में किया है, एक अलग "FileOpenService" वर्ग वास्तविक संवाद सहभागिता को संभालता है। इस तरह आप परीक्षण के दौरान फ़ाइल खोलने की सेवा को नकली कर सकते हैं। इस तरह के कोड को एक अलग सेवा में रखने से आपको फिर से अच्छे परिणाम मिल सकते हैं। :)
पीटर लिलेवॉल्ड

2

प्रस्तुतकर्ता को आपके द्वारा सुझाए गए अनुरोध के अनुसार ओपनफिल्डियलॉग विंडो दिखाना चाहिए। चूंकि प्रस्तुतकर्ता मॉडल से कोई डेटा आवश्यक नहीं है, और अनुरोध को संभालना चाहिए।

मान लें कि आपको अपने मॉडल में कुछ इकाइयां बनाने के लिए डेटा की आवश्यकता है। आप या तो स्ट्रीम ट्रेंच को एक्सेस लेयर में पास कर सकते हैं जहाँ आपके पास स्ट्रीम से इकाइयाँ बनाने की विधि है, लेकिन मेरा सुझाव है कि आप अपने प्रस्तुतकर्ता में फ़ाइल के पार्सिंग को हैंडल करें और अपने मॉडल में एक कंस्ट्रक्टर या प्रति इकाई बनाएँ विधि का उपयोग करें।


1
जवाब के लिए धन्यवाद। इसके अलावा, क्या आपके पास दृश्य के लिए एक भी प्रस्तुतकर्ता होगा? और वह प्रस्तुतकर्ता या तो अनुरोध को संभालता है, या यदि डेटा की आवश्यकता होती है, तो यह किसी भी संख्या में मॉडल कक्षाओं को दर्शाता है जो विशिष्ट अनुरोधों पर कार्य करते हैं? क्या यह सही तरीका है? एक बार फिर धन्यवाद।
डैरेन यंग

3
एक दृश्य में एक प्रस्तुतकर्ता होता है, लेकिन एक प्रस्तुतकर्ता के कई विचार हो सकते हैं।
जोकेमेकपे
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.