ViewModelLocator nedir ve DataTemplates'e kıyasla artıları / eksileri nelerdir?


112

Birisi bana ViewModelLocator'ın ne olduğu, nasıl çalıştığı ve DataTemplates'e kıyasla onu kullanmanın artıları / eksileri hakkında hızlı bir özet verebilir mi?

Google'da bilgi bulmaya çalıştım, ancak bunun birçok farklı uygulaması var gibi görünüyor ve ne olduğu ve kullanmanın artıları / eksileri konusunda bir liste yok.

Yanıtlar:


204

giriş

MVVM'de olağan uygulama, Görünümlerin ViewModel'lerini bir bağımlılık enjeksiyon (DI) konteynerinden çözerek bulmalarını sağlamaktır . Bu, kapsayıcıdan View sınıfının bir örneğini sağlaması (çözümlemesi) istendiğinde otomatik olarak gerçekleşir. Kap , ViewModel parametresini kabul eden View yapıcısını çağırarak ViewModel'i View'e enjekte eder ; bu şemaya kontrolün tersine çevrilmesi (IoC) denir .

DI'nin Faydaları

Buradaki ana fayda, kapsayıcının kendisinden istediğimiz türlerin nasıl çözüleceğine ilişkin talimatlarla çalışma zamanında yapılandırılabilmesidir . Bu, uygulamamız gerçekten çalıştığında kullandığımız türleri (Görünümler ve ViewModels) çözme talimatı vererek, ancak uygulama için birim testlerini çalıştırırken farklı şekilde talimat vererek daha fazla test edilebilirlik sağlar. İkinci durumda, uygulamanın bir UI'si bile olmayacaktır (çalışmıyor; sadece testler), bu nedenle kapsayıcı , uygulama çalışırken kullanılan "normal" türlerin yerine taklitleri çözecektir .

DI'dan kaynaklanan sorunlar

Şimdiye kadar, DI yaklaşımının, uygulama bileşenlerinin oluşturulması üzerine bir soyutlama katmanı ekleyerek uygulama için kolay test edilebilirlik sağladığını gördük. Bu yaklaşımla ilgili bir sorun var: Microsoft Expression Blend gibi görsel tasarımcılarla iyi oynamıyor .

Sorun, hem normal uygulama çalıştırmalarında hem de birim test çalıştırmalarında, birisinin kapsayıcıyı hangi türlerin çözüleceğine ilişkin talimatlarla kurması gerektiğidir; ek olarak, ViewModellerin bunlara enjekte edilebilmesi için birisinin konteynerden Görünümleri çözmesini istemesi gerekir.

Bununla birlikte, tasarım zamanında çalışan bir kodumuz yoktur . Tasarımcı, Görünümlerimizin örneklerini oluşturmak için yansımayı kullanmaya çalışır, bu şu anlama gelir:

  • View yapıcısı bir ViewModel örneği gerektiriyorsa, tasarımcı Görünümü hiç başlatamaz - kontrollü bir şekilde hata verir.
  • Görünüm parametresiz yapıcı varsa gör örneği, ancak onun DataContextolacak nullbiz 'tasarımcı bir 'boş' bir görünüm elde edeceğiz böylece - çok kullanışlı değildir

ViewModelLocator'a girin

ViewModelLocator, şu şekilde kullanılan ek bir soyutlamadır:

  • View, kaynaklarının bir parçası olarak bir ViewModelLocator oluşturur ve DataContext'i konumlandırıcının ViewModel özelliğine veri bağlar.
  • Konum belirleyici , tasarım modunda olup olmadığımızı bir şekilde algılar.
  • Tasarım modunda değilse, yer belirleyici yukarıda açıklandığı gibi DI konteynerinden çözdüğü bir ViewModel döndürür.
  • Tasarım modundaysa, konumlandırıcı kendi mantığını kullanarak sabit bir "kukla" ViewModel döndürür (unutmayın: tasarım zamanında kap yoktur!); bu ViewModel tipik olarak kukla verilerle önceden doldurulmuş olarak gelir

Elbette bu, Görünüm'ün başlamak için parametresiz bir kurucuya sahip olması gerektiği anlamına gelir (aksi takdirde tasarımcı onu başlatamaz).

özet

ViewModelLocator, DI'nin avantajlarını MVVM uygulamanızda tutmanıza ve aynı zamanda kodunuzun görsel tasarımcılarla iyi oynamasına izin veren bir deyimdir. Bu bazen uygulamanızın "karıştırılabilirliği" olarak adlandırılır (İfade Karışımına atıfta bulunarak).

Yukarıdakileri sindirdikten sonra, burada pratik bir örneğe bakın .

Son olarak, veri şablonlarını kullanmak, ViewModelLocator'ı kullanmaya bir alternatif değil, kullanıcı arayüzünüzün bölümleri için açık View / ViewModel çiftlerini kullanmaya bir alternatiftir. Bunun yerine bir veri şablonu kullanabileceğiniz için, genellikle bir ViewModel için bir Görünüm tanımlamanıza gerek olmadığını fark edebilirsiniz.


4
Harika bir açıklama için +1. Görünüm ve Kaynaklarını daha da genişletebilir misiniz? Kaynaklar derken, Görünümün özelliklerini mi kastediyorsunuz? Veya? Bu modele somut bir örnekle bağlantınız var mı?
Metro Smurf

@MetroSmurf: Bağlantınız Özet bölümünde.
Jon

1
Teşekkürler. ViewModelLocator kullanmanın herhangi bir sınırlaması var mı? Statik bir kaynağa başvurduğu gerçeğiyle ilgili bazı endişelerim vardı - ViewModels çalışma zamanında dinamik olarak oluşturulabilir mi? Ve birini bağlamakla ilgili çok fazla ekstra kod var mı?
Rachel

@Rachel: Özetteki aynı bağlantı bu soruları pratik örneklerle yanıtlamalıdır.
Jon

2
Son derece yanıltıcı cevap. View Model Locator'ın birincil amacı, tasarımcıya sahte veriler sağlamak değildir. Bunu belirterek kolayca yapabilirsiniz d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}". Konumlandırıcının amacı aslında Görünümlerde DI'yi etkinleştirmektir, çünkü WPF bunu sağlamakta çok kötüdür. Örnek: bazı İletişim Pencerelerini açan bir Ana Pencereniz var. Diyalog Penceresindeki DI'yi olağan şekilde çözmek için, Ana Pencereye bağımlılık olarak bunu iletmeniz gerekir! Bu, View Locator ile önlenir.
hyankov

10

@ Jon'un cevabının bir örnek uygulaması

Görünüm modeli bulucu sınıfım var. Her özellik, benim görüşüme tahsis edeceğim görünüm modelinin bir örneği olacak. Kodun tasarım modunda çalışıp çalışmadığını kontrol edebilirim DesignerProperties.GetIsInDesignMode. Bu, tasarım sırasında sahte bir model ve uygulamayı çalıştırdığımda gerçek nesneyi kullanmama izin veriyor.

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);
    }
}

Ve onu kullanmak için konumlandırıcımı App.xamlkaynaklara ekleyebilirim :

xmlns:core="clr-namespace:MyViewModelLocatorNamespace"

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

Ve sonra görünümünüzü (ör. MainView.xaml) görünüm modelinize bağlamak için:

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

thisyerine kullanımda herhangi bir fark var dummymı?
Sebastian Xawery Wiśniowiecki

5

Bu sorunun diğer yanıtlarının neden Tasarımcının etrafında dolaştığını anlamıyorum.

View Model Locator'ın amacı, View'unuzun bunu somutlaştırmasına izin vermektir (evet, View Model Locator = Önce Görüntüle):

public void MyWindowViewModel(IService someService)
{
}

sadece bunun yerine:

public void MyWindowViewModel()
{
}

bunu ilan ederek:

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

ViewModelLocatorBir IoC'ye başvuran sınıf nerede ve MainWindowModelaçığa çıkardığı özelliği bu şekilde çözüyor .

Görünümünüze Mock görünüm modelleri sağlamakla hiçbir ilgisi yoktur. Eğer bunu istiyorsan, sadece yap

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

View Model Locator, örneğin Unity gibi bazı (herhangi bir) Kontrolün Tersine Çevrilmesi konteynerinin etrafındaki bir sarmalayıcıdır.

Şunlara bakın:


Görünüm modeli bulucu bir kap gerektirmez, kullanıcı, görünüm modelinin yapılandırma yoluyla nasıl çözüleceğine karar verir ve bir kap kullanabilir veya bir türü kendiniz yenileyebilirsiniz. Böylece, örneğin tüm görünümlerinizi önceden kaydetmek ve bazı konteynerlerdeki modelleri görüntülemek yerine, konvansiyona dayalı görünüm modeli konumu yapabilirsiniz.
Chris Bordeman

" Diğer yanıtların neden [...] Tasarımcının etrafına sarıldığını anlamıyorum " +1 derken haklısınız , ancak konum belirleyicinin amacı, görünüm modelinin nasıl olduğuna dair herhangi bir bilgiyi görünümden çıkarmaktır. görünümü bu somutlaştırmadan bağımsız hale getirerek, bunu konumlayıcıya bırakarak. Konum belirleyici, görünüm modelinin farklı tatlarını sağlayabilir, belki de bulucunun yöneteceği eklentiler aracılığıyla eklenen bazı özel olanlar (ve tasarım süresi için belirli bir tane). Görünüm, görünüm modelinin doğru sürümünü bulmaya yönelik bu işlemin herhangi birinden temiz olacaktır, bu gerçekten SoC için iyidir.
dakika
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.