2011-01-25 23 views
80

में मॉडल-व्यू-प्रेजेंटर मैं WinForms का उपयोग करके पहली बार एमवीपी विधि को लागू करने की कोशिश कर रहा हूं।WinForms

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

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

तो एमवीपी का उपयोग करके, जीयूआई बटन क्लिक ईवेंट को संभालता है और फिर presenter.openfile() को कॉल करता है;

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

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

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

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

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

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

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

मुझे लगता है कि वे मेरी मुख्य चिंताओं हैं और यदि मैं समझता हूं कि इनके लिए प्रवाह कैसे होना चाहिए, मुझे लगता है कि मैं ठीक हूं।

+0

यह लिंक http://lostechies.com/derekgreer/2008/11/23/model-view-presenter-styles/ एमवीपी की कुछ शैलियों को बताता है। यह जोहान के उत्कृष्ट उत्तर के अलावा सहायक साबित हो सकता है। – ak3nat0n

उत्तर

110

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

पहले, कुछ भी है कि एक उपयोगकर्ता के साथ बातचीत कर सकते हैं, या बस से दिखाया जा, एक दृश्य है। इस तरह के दृश्य के कानून, व्यवहार और विशेषताओं का वर्णन इंटरफ़ेस द्वारा किया गया है। उस इंटरफ़ेस को 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.WinForm लोड हो जाए, यह एक treeview प्राप्त करने के लिए है जब। क्या मैं यह सोचने में सही हूं कि दृश्य को एक विधि जैसे कि presenter.gettree() को कॉल करना चाहिए, यह बदले में मॉडल को प्रतिनिधि करेगा, जो वृक्षदृश्य के लिए डेटा प्राप्त करेगा, इसे बनाएगा और इसे कॉन्फ़िगर करेगा, इसे वापस लौटाएगा प्रेजेंटर, जो बदले में दृश्य को पास करेगा जो तब इसे एक पैनल कहने के लिए असाइन करेगा?

मैं सही IConfigurationView.Show()

2.को कॉल करने से पहले IConfigurationPresenter.ShowView() से IConfigurationView.SetTreeData(...) कहेंगे, इस Winform पर कोई डेटा नियंत्रण के लिए एक ही होगा, के रूप में मैं भी एक DataGridView है ?

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

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

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

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

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

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

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

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

+2

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

+10

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

+4

@lejon: यदि दूसरी ओर, दृश्य केवल वास्तविक घटना का खुलासा करता है, तो प्रस्तुतकर्ता स्वयं (जो जानता है कि दृश्य ईवेंट होने पर वह क्या करना चाहता है) बस सही चीज़ करने के लिए इसकी सदस्यता लेता है। यह केवल "जटिलता का एक बिंदु" है, जो मेरी पुस्तक में "जटिलता के 2 अंक" के रूप में दोगुना है। आम तौर पर, कम युग्मन का मतलब एक परियोजना के संचालन पर कम रखरखाव लागत है। –

2

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

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

+1

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

+3

ए व्यू में एक प्रेजेंटर है लेकिन एक प्रस्तुतकर्ता के पास कई विचार हो सकते हैं। – JochemKempe

10

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

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

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

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

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

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

+0

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

+3

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