एक ViewModelLocator क्या है और DataTemplates की तुलना में इसके पेशेवरों / विपक्ष क्या हैं?


112

क्या कोई मुझे एक त्वरित सारांश दे सकता है कि एक ViewModelLocator क्या है, यह कैसे काम करता है, और DataTemplates की तुलना में इसका उपयोग करने के लिए क्या पेशेवरों / विपक्ष हैं?

मैंने Google पर जानकारी ढूंढने की कोशिश की है, लेकिन इसके कई अलग-अलग कार्यान्वयन हैं और इसका उपयोग करने के पेशेवरों / विपक्षों के रूप में कोई स्ट्रिपगेट सूची नहीं है।

जवाबों:


204

पहचान

एमवीवीएम में सामान्य अभ्यास यह है कि उनके दृश्यमॉडल को एक निर्भरता इंजेक्शन (डीआई) कंटेनर से हल करके नजारे खोजे जाएं । यह स्वचालित रूप से होता है जब कंटेनर को व्यू क्लास का एक उदाहरण प्रदान करने (समाधान) के लिए कहा जाता है। कंटेनर ViewModel को दृश्य के एक निर्माता को कॉल करके View में इंजेक्ट करता है जो एक ViewModel पैरामीटर को स्वीकार करता है; इस योजना को नियंत्रण का उलटा (IoC) कहा जाता है

DI के लाभ

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

DI से उपजी समस्याएं

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

समस्या यह है कि सामान्य अनुप्रयोग रन और यूनिट टेस्ट रन दोनों में, किसी को कंटेनर को निर्देश के साथ सेट करना होगा कि किस प्रकार को हल करना है; इसके अलावा, किसी को कंटेनर को व्यूज़ को हल करने के लिए कहना होगा ताकि व्यूमॉडल को उसमें इंजेक्ट किया जा सके।

हालाँकि, डिज़ाइन समय में हमारा कोई कोड नहीं चल रहा है । डिजाइनर हमारे दृश्यों के उदाहरण बनाने के लिए प्रतिबिंब का उपयोग करने का प्रयास करता है, जिसका अर्थ है कि:

  • यदि व्यू कंस्ट्रक्टर को ViewModel उदाहरण की आवश्यकता होती है, तो डिज़ाइनर व्यू को तुरंत देख नहीं पाएगा - यह किसी न किसी तरीके से त्रुटि करेगा
  • यदि व्यू में एक पैरामीटर रहित कंस्ट्रक्टर है, तो व्यू को त्वरित रूप से बदल दिया DataContextजाएगा , लेकिन इसका परिणाम यह होगा nullकि हमें डिजाइनर में "खाली" दृश्य मिलेगा - जो बहुत उपयोगी नहीं है

ViewModelLocator दर्ज करें

ViewModelLocator इस तरह उपयोग किया जाने वाला एक अतिरिक्त अमूर्त है:

  • व्यू अपने आप को अपने संसाधनों के एक हिस्से के रूप में एक ViewModelLocator झटपट करता है और लोकेटर के ViewModel संपत्ति के लिए अपने DataContext को डेटाबाइंड करता है।
  • लोकेटर किसी तरह पता लगाता है कि क्या हम डिजाइन मोड में हैं
  • यदि डिज़ाइन मोड में नहीं है, तो लोकेटर एक ViewModel देता है जिसे वह DI कंटेनर से हल करता है, जैसा कि ऊपर बताया गया है
  • यदि डिजाइन मोड में, लोकेटर एक निश्चित "डमी" ViewModel को अपने तर्क का उपयोग करके लौटाता है (याद रखें: डिजाइन समय में कोई कंटेनर नहीं है!)। यह ViewModel आमतौर पर डमी डेटा के साथ आता है

बेशक इसका मतलब यह है कि व्यू के पास एक पैरामीटर रहित कंस्ट्रक्टर होना चाहिए, जिसके साथ शुरुआत होगी (अन्यथा डिजाइनर इसे तुरंत इंस्टाल नहीं कर पाएगा)।

सारांश

ViewModelLocator एक मुहावरा है जो आपको अपने MVVM एप्लिकेशन में DI के लाभों को रखने की अनुमति देता है जबकि आपके कोड को दृश्य डिजाइनरों के साथ अच्छा खेलने की अनुमति देता है। इसे कभी-कभी आपके आवेदन की "मिश्रणशीलता" कहा जाता है (अभिव्यक्ति मिश्रण की चर्चा करते हुए)।

ऊपर पचाने के बाद, एक व्यावहारिक उदाहरण देखने के लिए यहाँ

अंत में, डेटा टेम्प्लेट का उपयोग करना ViewModelLocator का उपयोग करने का विकल्प नहीं है, लेकिन आपके UI के कुछ हिस्सों के लिए स्पष्ट दृश्य / ViewModel जोड़े का उपयोग करने का विकल्प है। अक्सर आप पा सकते हैं कि एक ViewModel के लिए एक दृश्य को परिभाषित करने की कोई आवश्यकता नहीं है क्योंकि आप इसके बजाय डेटा टेम्पलेट का उपयोग कर सकते हैं।


4
एक महान विवरण के लिए +1। क्या आप व्यू और इसके संसाधनों पर और विस्तार कर सकते हैं? संसाधन द्वारा, क्या आप देखें के गुणों का मतलब है? या? क्या आपके पास इस पैटर्न के लिए एक ठोस उदाहरण के साथ एक लिंक है?
मेट्रो स्मर्फ

@MetroSmurf: आपका लिंक सारांश अनुभाग में है।
जॉन

1
धन्यवाद। क्या ViewModelLocator का उपयोग करने की कोई सीमाएँ हैं? मुझे इस तथ्य के बारे में कुछ चिंताएं थीं कि यह एक स्थिर संसाधन का संदर्भ देता है - क्या व्यूमॉडल्स को गतिशील रूप से रनटाइम पर बनाया जा सकता है? और क्या एक को जोड़ने के लिए बहुत सारे अतिरिक्त कोड शामिल हैं?
राहेल

@ राचल: सारांश में उसी लिंक को व्यावहारिक उदाहरणों के साथ इन सवालों का जवाब देना चाहिए।
जॉन

2
बेहद भ्रामक जवाब। व्यू मॉडल लोकेटर का प्राथमिक उद्देश्य डिजाइनर को डमी डेटा प्रदान करना नहीं है। आप इसे निर्दिष्ट करके आसानी से कर सकते हैं d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"। लोकेटर का उद्देश्य वास्तव में डि को दृश्य पर सक्षम करना है, क्योंकि WPF इसे प्रदान करने में बहुत खराब है। उदाहरण: आपके पास एक मुख्य विंडो है जो कुछ डायलॉग विंडो खोलता है। सामान्य रूप से डायल विंडो पर DI को हल करने के लिए, आपको इसे मुख्य विंडो पर निर्भरता के रूप में पारित करना होगा! यह दृश्य लोकेटर से बचा जाता है।
संकरकोण

10

@ जॉन के जवाब का एक उदाहरण कार्यान्वयन

मेरे पास एक दृश्य मॉडल लोकेटर वर्ग है। प्रत्येक गुण दृश्य मॉडल का एक उदाहरण होने जा रहा है जिसे मैं अपने दृश्य पर आवंटित करने जा रहा हूं। मैं जांच सकता हूं कि कोड डिजाइन मोड में चल रहा है या नहीं DesignerProperties.GetIsInDesignMode। जब मैं एप्लिकेशन चला रहा होता हूं, तो मुझे डिजाइनिंग के समय और वास्तविक वस्तु के दौरान एक नकली मॉडल का उपयोग करने की अनुमति देता है।

public class ViewModelLocator
{
    private DependencyObject dummy = new DependencyObject();

    public IMainViewModel MainViewModel
    {
        get
        {
            if (IsInDesignMode())
            {
                return new MockMainViewModel();
            }

            return MyIoC.Container.GetExportedValue<IMainViewModel>();
        }
    }

    // returns true if editing .xaml file in VS for example
    private bool IsInDesignMode()
    {
        return DesignerProperties.GetIsInDesignMode(dummy);
    }
}

और इसका उपयोग करने के लिए मैं अपने लोकेटर को App.xamlसंसाधनों में जोड़ सकता हूं :

xmlns:core="clr-namespace:MyViewModelLocatorNamespace"

<Application.Resources>
    <core:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>

और फिर अपने दृश्य को तार करने के लिए (उदा: MainView.xaml) को अपने दृश्यमॉडल में:

<Window ...
  DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">

क्या thisइसके बजाय उपयोग करने में कोई अंतर है dummy?
सेबेस्टियन ज़ावरी वाईनोनीकी

5

मुझे समझ में नहीं आता है कि इस प्रश्न के अन्य उत्तर डिजाइनर के आसपास क्यों हैं।

मॉडल लोकेटर को देखने का उद्देश्य यह है कि आप अपने दृश्य को तुरंत देख सकें (हां, मॉडल लोकेटर देखें = पहले देखें):

public void MyWindowViewModel(IService someService)
{
}

इसके बजाय बस:

public void MyWindowViewModel()
{
}

यह घोषित करके:

DataContext="{Binding MainWindowModel, Source={StaticResource ViewModelLocator}}"

ViewModelLocatorवर्ग कहां है, जो एक आईओसी का संदर्भ देता है और वह यह है कि यह उस MainWindowModelसंपत्ति को कैसे हल करता है जिसे वह उजागर करता है।

इसका आपके विचार को मॉक व्यू मॉडल प्रदान करने से कोई लेना-देना नहीं है। अगर आप ऐसा चाहते हैं, तो बस करें

d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"

देखें मॉडल लोकेटर नियंत्रण के कंटेनर के कुछ (किसी भी) उलटा के आसपास एक आवरण है, जैसे कि उदाहरण के लिए एकता।

को देखें:


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

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