Share via


Model-View-ViewModel Deseni

Not

Bu e-Kitap 2017 baharında yayımlanmıştır ve o zamandan beri güncelleştirilmemiştir. Kitapta değerli kalan çok şey var, ancak bazı malzemeler güncelliğini yitirmiş.

Xamarin.Forms Geliştirici deneyimi genellikle XAML'de bir kullanıcı arabirimi oluşturmayı ve ardından kullanıcı arabiriminde çalışan arka planda kod eklemeyi içerir. Uygulamalar değiştirilip boyut ve kapsam olarak büyüdükçe karmaşık bakım sorunları ortaya çıkabilir. Bu sorunlar, kullanıcı arabirimi denetimleri ile iş mantığı arasındaki sıkı eşleştirmeyi içerir ve bu da kullanıcı arabirimi değişiklikleri yapma maliyetini artırır ve bu tür kodların birim test edilmesi zorluğunu içerir.

Model-View-ViewModel (MVVM) deseni, bir uygulamanın iş ve sunu mantığını kullanıcı arabiriminden (UI) temiz bir şekilde ayırmaya yardımcı olur. Uygulama mantığı ve kullanıcı arabirimi arasında temiz bir ayrım yapılması, çok sayıda geliştirme sorununun giderilmesine yardımcı olur ve uygulamanın testini, bakımını yapmasını ve gelişmesini kolaylaştırabilir. Ayrıca kod yeniden kullanım fırsatlarını büyük ölçüde geliştirebilir ve geliştiricilerin ve kullanıcı arabirimi tasarımcılarının bir uygulamanın ilgili bölümlerini geliştirirken daha kolay işbirliği yapmasına olanak tanır.

MVVM Düzeni

MVVM deseninde üç temel bileşen vardır: model, görünüm ve görünüm modeli. Her birinin ayrı bir amacı vardır. Şekil 2-1'de üç bileşen arasındaki ilişkiler gösterilmektedir.

The MVVM pattern

Şekil 2-1: MVVM deseni

Her bileşenin sorumluluklarını anlamanın yanı sıra, birbirleriyle nasıl etkileşime geçtiğini anlamak da önemlidir. Yüksek düzeyde görünüm modeli "bilir", görünüm modeli ise modeli "bilir", ancak model görünüm modelinin farkında değildir ve görünüm modeli görünümün farkında değildir. Bu nedenle, görünüm modeli görünümü modelden yalıtarak modelin görünümden bağımsız olarak gelişmesine olanak tanır.

MVVM desenini kullanmanın avantajları şunlardır:

  • Mevcut iş mantığını kapsülleyen bir model uygulaması varsa, bunu değiştirmek zor veya riskli olabilir. Bu senaryoda, görünüm modeli model sınıfları için bir bağdaştırıcı işlevi görür ve model kodunda önemli değişiklikler yapmaktan kaçınmanızı sağlar.
  • Geliştiriciler görünümü kullanmadan görünüm modeli ve model için birim testleri oluşturabilir. Görünüm modelinin birim testleri, görünüm tarafından kullanılan işlevlerin tam olarak aynısını kullanabilir.
  • Görünümün tamamen XAML'de uygulanması koşuluyla uygulama kullanıcı arabirimi koda dokunmadan yeniden tasarlanabilir. Bu nedenle, görünümün yeni bir sürümü mevcut görünüm modeliyle çalışmalıdır.
  • Tasarım Aracı ve geliştiriciler, geliştirme sürecinde bileşenleri üzerinde bağımsız ve eşzamanlı olarak çalışabilir. Tasarım Aracı görünüme odaklanabilirken, geliştiriciler görünüm modeli ve model bileşenleri üzerinde çalışabilir.

MVVM'yi etkili bir şekilde kullanmanın anahtarı, uygulama kodunun doğru sınıflara nasıl dahil yapılacağını anlamak ve sınıfların nasıl etkileşim kuracaklarını anlamaktır. Aşağıdaki bölümlerde, MVVM düzenindeki sınıfların her birinin sorumlulukları açıklanmıştır.

Görünüm

Görünüm, kullanıcının ekranda gördüklerinin yapısını, düzenini ve görünümünü tanımlamakla sorumludur. İdeal olan, her görünümün iş mantığı içermeyen sınırlı bir arka planda kodla XAML'de tanımlanmasıdır. Ancak, bazı durumlarda arka planda kod, animasyonlar gibi XAML'de ifade edilmesi zor olan görsel davranışlar uygulayan ui mantığı içerebilir.

Xamarin.Forms Bir uygulamada görünüm genellikle Page-derived veya ContentView-derived sınıfıdır. Ancak görünümler, görüntülendiğinde bir nesneyi görsel olarak temsil etmek için kullanılacak kullanıcı arabirimi öğelerini belirten bir veri şablonuyla da temsil edilebilir. Görünüm olarak veri şablonunun arka planında kod yoktur ve belirli bir görünüm modeli türüne bağlanacak şekilde tasarlanmıştır.

İpucu

Arka planda bulunan ui öğelerini etkinleştirmekten ve devre dışı bırakmaktan kaçının. Görünüm modellerinin, bir komutun kullanılabilir olup olmadığı veya işlemin beklemede olduğunu gösteren bir gösterge gibi görünümün görünümünün bazı yönlerini etkileyen mantıksal durum değişiklikleri tanımlamakla sorumlu olduğundan emin olun. Bu nedenle, kullanıcı arabirimi öğelerini arka planda etkinleştirmek ve devre dışı bırakmak yerine model özelliklerini görüntülemek üzere bağlayarak etkinleştirin ve devre dışı bırakın.

Görünümdeki etkileşimlere yanıt olarak görünüm modelinde kod yürütmek için düğme tıklaması veya öğe seçimi gibi çeşitli seçenekler vardır. Denetim komutları destekliyorsa, denetimin Command özelliği görünüm modelinde bir ICommand özelliğe veri bağlanabilir. Denetimin komutu çağrıldığında, görünüm modelindeki kod yürütülür. Komutlara ek olarak, davranışlar görünümdeki bir nesneye eklenebilir ve çağrılacak komutu veya tetiklenecek olayı dinleyebilir. Buna yanıt olarak, davranış görünüm modelinde veya ICommand görünüm modelinde bir yöntem çağırabilir.

ViewModel

Görünüm modeli, görünümün bağlanabileceği özellikler ve komutlar uygular ve değişiklik bildirimi olayları aracılığıyla durum değişikliklerinin görünümünü bildirir. Görünüm modelinin sağladığı özellikler ve komutlar, kullanıcı arabirimi tarafından sunulacak işlevselliği tanımlar, ancak görünüm bu işlevselliğin nasıl görüntüleneceğini belirler.

İpucu

Zaman uyumsuz işlemlerle kullanıcı arabiriminin yanıt vermesini sağlayın. Mobil uygulamalar, kullanıcının performans algısını geliştirmek için kullanıcı arabirimi iş parçacığının engelini kaldırmalıdır. Bu nedenle, görünüm modelinde G/Ç işlemleri için zaman uyumsuz yöntemler kullanın ve özellik değişikliklerini zaman uyumsuz olarak görünümlere bildirmek için olayları tetikleyin.

Görünüm modeli, görünümün gerekli olan tüm model sınıfları ile etkileşimlerini koordine etmekle de sorumludur. Görünüm modeli ile model sınıfları arasında genellikle bire çok ilişkisi vardır. Görünüm modeli, görünümdeki denetimlerin verilere doğrudan bağlanabilmesi için model sınıflarını doğrudan görünüme göstermeyi seçebilir. Bu durumda, model sınıflarının veri bağlamayı destekleyecek ve bildirim olaylarını değiştirecek şekilde tasarlanması gerekir.

Her görünüm modeli, bir modelden görünümün kolayca kullanabileceği bir formda veri sağlar. Bunu başarmak için görünüm modeli bazen veri dönüştürme gerçekleştirir. Görünümün bağlanabileceği özellikler sağladığından, bu veri dönüştürmeyi görünüm modeline yerleştirmek iyi bir fikirdir. Örneğin, görünüm modeli iki özelliğin değerlerini birleştirerek görünümün görüntülenmesini kolaylaştırabilir.

İpucu

Veri dönüştürmelerini bir dönüştürme katmanında merkezi hale getirin. Ayrıca dönüştürücüleri, görünüm modeliyle görünüm arasında yer alan ayrı bir veri dönüştürme katmanı olarak kullanmak da mümkündür. Örneğin, veriler görünüm modelinin sağlamadığı özel biçimlendirme gerektirdiğinde bu gerekli olabilir.

Görünüm modelinin görünümle iki yönlü veri bağlamaya katılması için, özelliklerinin olayı tetiklemesi PropertyChanged gerekir. Görünüm modelleri arabirimini uygulayarak INotifyPropertyChanged ve bir özellik değiştirildiğinde olayı oluşturarak PropertyChanged bu gereksinimi karşılar.

Koleksiyonlar için görünümü kolay ObservableCollection<T> sağlanır. Bu koleksiyon, koleksiyon değişikliği bildirimini uygulayarak geliştiricinin koleksiyonlarda arabirimi uygulamasına INotifyCollectionChanged gerek kalmadan bunu uygular.

Model

Model sınıfları, uygulamanın verilerini kapsülleyen görsel olmayan sınıflardır. Bu nedenle, modelin genellikle iş ve doğrulama mantığıyla birlikte bir veri modeli içeren uygulamanın etki alanı modelini temsil ettiği düşünülebilir. Model nesnelerine örnek olarak veri aktarım nesneleri (DTO'lar), Düz Eski CLR Nesneleri (POCO'lar) ve oluşturulan varlık ve ara sunucu nesneleri verilebilir.

Model sınıfları genellikle veri erişimini ve önbelleğe almayı kapsülleyen hizmetler veya depolarla birlikte kullanılır.

Görünüm Modellerini Görünümlere Bağlan

Görünüm modelleri, veri bağlama özellikleri kullanılarak görünümlere Xamarin.Formsbağlanabilir. Görünümleri oluşturmak ve modelleri görüntülemek ve çalışma zamanında ilişkilendirmek için kullanılabilecek birçok yaklaşım vardır. Bu yaklaşımlar, ilk kompozisyonu görüntüle ve model ilk bileşimini görüntüle olarak bilinen iki kategoriye ayrılır. İlk kompozisyonu görüntüleme ve model ilk bileşimini görüntüleme arasında seçim, tercih ve karmaşıklık sorunudur. Ancak, tüm yaklaşımlar görünümün BindingContext özelliğine atanmış bir görünüm modeline sahip olması için aynı amacı paylaşır.

Görünüm ilk bileşimi ile uygulama kavramsal olarak bağımlı oldukları görünüm modellerine bağlanan görünümlerden oluşur. Bu yaklaşımın birincil avantajı, görünüm modellerinin görünümlere hiçbir bağımlılığı olmadığından gevşek bir şekilde bağlanmış, birim test edilebilir uygulamalar oluşturmanın kolay hale getirmesidir. Ayrıca, sınıfların nasıl oluşturulduğunu ve ilişkili olduğunu anlamak için kod yürütmeyi izlemek zorunda kalmadan görsel yapısını izleyerek uygulamanın yapısını anlamak da kolaydır. Buna ek olarak, ilk görünüm yapısı, gezinti gerçekleştiğinde sayfaların oluşturulmasından sorumlu olan gezinti sistemiyle Xamarin.Forms uyumludur ve bu da bir görünüm modelinin ilk bileşimini karmaşık hale getirir ve platformla yanlış hizalanır.

Görünüm modelinin ilk bileşimiyle uygulama kavramsal olarak görünüm modellerinden oluşur ve bir hizmet görünüm modelinin görünümünü bulmakla sorumludur. Görünüm oluşturma işlemi soyutlanabilir ve uygulamanın kullanıcı arabirimi olmayan mantıksal yapısına odaklanmalarına olanak tanıyabildiğinden, görünüm ilk bileşimi bazı geliştiriciler için daha doğaldır. Buna ek olarak, görünüm modellerinin diğer görünüm modelleri tarafından oluşturulmasına izin verir. Ancak bu yaklaşım genellikle karmaşıktır ve uygulamanın çeşitli bölümlerinin nasıl oluşturulduğunu ve ilişkilendirildiğinden anlamak zor olabilir.

İpucu

Görünüm modellerini ve görünümleri bağımsız tutun. Görünümlerin veri kaynağındaki bir özelliğe bağlanması, görünümün ilgili görünüm modeline bağımlı olması gerekir. Özellikle, görünüm modellerinden ve ListViewgibi Button görünüm türlerine başvurmayın. Burada belirtilen ilkelere uyularak, görünüm modelleri yalıtılmış olarak test edilebilir, bu nedenle kapsamı sınırlayarak yazılım hatası olasılığını azaltır.

Aşağıdaki bölümlerde görünüm modellerini görünümlere bağlamaya yönelik ana yaklaşımlar açıklanmaktadır.

Bildirimli Olarak Görünüm Modeli Oluşturma

En basit yaklaşım, görünümün XAML'de ilgili görünüm modelini bildirimli olarak oluşturmasıdır. Görünüm oluşturulduğunda, ilgili görünüm modeli nesnesi de oluşturulur. Bu yaklaşım aşağıdaki kod örneğinde gösterilmiştir:

<ContentPage ... xmlns:local="clr-namespace:eShop">  
    <ContentPage.BindingContext>  
        <local:LoginViewModel />  
    </ContentPage.BindingContext>  
    ...  
</ContentPage>

ContentPage oluşturulduğunda, öğesinin LoginViewModel bir örneği otomatik olarak oluşturulur ve görünümün BindingContextolarak ayarlanır.

Görünüm modelinin görünüme göre bu bildirim temelli yapısı ve ataması, basit olması avantajına sahiptir, ancak görünüm modelinde varsayılan (parametresiz) bir oluşturucu gerektirmesi dezavantajı vardır.

Program Aracılığıyla Görünüm Modeli Oluşturma

Bir görünümün arka planda kod dosyasında kodu olabilir ve bu da görünüm modelinin özelliğine atanmasıyla BindingContext sonuçlanabilir. Bu genellikle aşağıdaki kod örneğinde gösterildiği gibi görünümün oluşturucusunda gerçekleştirilir:

public LoginView()  
{  
    InitializeComponent();  
    BindingContext = new LoginViewModel(navigationService);  
}

Görünümün arka planındaki görünüm modelinin program aracılığıyla oluşturulması ve atanma özelliği basit olması avantajına sahiptir. Ancak, bu yaklaşımın temel dezavantajı görünümün görünüm modeline gerekli bağımlılıkları sağlaması gerektiğidir. Bağımlılık ekleme kapsayıcısı kullanmak, görünüm ve görünüm modeli arasında gevşek bağlantının korunmasına yardımcı olabilir. Daha fazla bilgi için bkz . Bağımlılık Ekleme.

Veri Şablonu Olarak Tanımlanan Görünüm Oluşturma

Görünüm, veri şablonu olarak tanımlanabilir ve bir görünüm modeli türüyle ilişkilendirilebilir. Veri şablonları kaynak olarak tanımlanabilir veya görünüm modelinin görüntüleneceği denetim içinde satır içinde tanımlanabilir. Denetimin içeriği görünüm modeli örneğidir ve veri şablonu bunu görsel olarak temsil etmek için kullanılır. Bu teknik, görünüm modelinin ilk olarak örneklendiği ve ardından görünümün oluşturulduğu bir durum örneğidir.

Görünüm Modeli Bulucu ile Otomatik Olarak Görünüm Modeli Oluşturma

Görünüm modeli bulucu, görünüm modellerinin ve görünümlerle ilişkilerinin örneğini yöneten özel bir sınıftır. eShopOnContainers mobil uygulamasında, sınıfın ViewModelLocator görünüm modellerini görünümlerle ilişkilendirmek için kullanılan ekli bir özelliği AutoWireViewModelvardır. Görünümün XAML'sinde, aşağıdaki kod örneğinde gösterildiği gibi görünüm modelinin görünüme otomatik olarak bağlanması gerektiğini belirtmek için bu ekli özellik true olarak ayarlanır:

viewModelBase:ViewModelLocator.AutoWireViewModel="true"

AutoWireViewModel özelliği false olarak başlatılan bağlanabilir bir özelliktir ve değeri değiştiğinde OnAutoWireViewModelChanged olay işleyicisi çağrılır. Bu yöntem görünümün görünüm modelini çözümler. Aşağıdaki kod örneğinde bunun nasıl başarıldığı gösterilmektedir:

private static void OnAutoWireViewModelChanged(BindableObject bindable, object oldValue, object newValue)  
{  
    var view = bindable as Element;  
    if (view == null)  
    {  
        return;  
    }  

    var viewType = view.GetType();  
    var viewName = viewType.FullName.Replace(".Views.", ".ViewModels.");  
    var viewAssemblyName = viewType.GetTypeInfo().Assembly.FullName;  
    var viewModelName = string.Format(  
        CultureInfo.InvariantCulture, "{0}Model, {1}", viewName, viewAssemblyName);  

    var viewModelType = Type.GetType(viewModelName);  
    if (viewModelType == null)  
    {  
        return;  
    }  
    var viewModel = _container.Resolve(viewModelType);  
    view.BindingContext = viewModel;  
}

yöntemi, OnAutoWireViewModelChanged kural tabanlı bir yaklaşım kullanarak görünüm modelini çözümlemeye çalışır. Bu kural, şu varsayımları kabul eder:

  • Görünüm modelleri, görünüm türleriyle aynı derlemededir.
  • Görünümler bir içindedir. Alt ad alanını görüntüler.
  • Görünüm modelleri bir içindedir. ViewModels alt ad alanı.
  • Görünüm modeli adları görünüm adlarıyla karşılık gelir ve "ViewModel" ile biter.

Son olarak yöntemi, OnAutoWireViewModelChanged görünüm türünün türünü çözümlenen görünüm modeli türüne ayarlar BindingContext . Görünüm modeli türünü çözümleme hakkında daha fazla bilgi için bkz . Çözümleme.

Bu yaklaşım, bir uygulamanın görünüm modellerinin örneğinden ve görünümlere olan bağlantılarından sorumlu olan tek bir sınıfa sahip olması avantajına sahiptir.

İpucu

Değiştirme kolaylığı için bir görünüm modeli bulucu kullanın. Görünüm modeli bulucu, birim testi veya tasarım zamanı verileri gibi alternatif bağımlılık uygulamaları için değiştirme noktası olarak da kullanılabilir.

Temel Görünüm Modelindeki veya Modeldeki Değişikliklere Yanıt Olarak Görünümleri Güncelleştirme

Görünümün erişebildiği tüm görünüm modeli ve model sınıfları arabirimini INotifyPropertyChanged uygulamalıdır. Bu arabirimin bir görünüm modeli veya model sınıfında uygulanması, temel alınan özellik değeri değiştiğinde sınıfın görünümdeki veriye bağlı denetimlere değişiklik bildirimleri sağlamasına olanak tanır.

Uygulamalar, aşağıdaki gereksinimleri karşılayarak özellik değişikliği bildiriminin doğru kullanımı için tasarlanmalıdır:

  • Ortak özelliğin PropertyChanged değeri değişirse her zaman bir olay oluşturur. XAML bağlamasının PropertyChanged nasıl gerçekleştiği bilgisi nedeniyle olayı yükseltmenin yoksayılabilir olduğunu varsaymayın.
  • Değerleri görünüm modelindeki veya modeldeki diğer özellikler tarafından kullanılan tüm hesaplanan özellikler için her zaman bir PropertyChanged olay oluşturur.
  • Her zaman bir özellik değişikliği yapan yöntemin sonunda veya nesnenin güvenli bir durumda olduğu bilindiğinde olayı yükseltin PropertyChanged . Olayın yükseltilmesi, olayın işleyicilerini zaman uyumlu bir şekilde çağırarak işlemi kesintiye uğratır. Bu bir işlemin ortasında gerçekleşirse, nesne güvenli olmayan, kısmen güncelleştirilmiş bir durumdayken geri çağırma işlevlerine maruz kalabilir. Buna ek olarak, basamaklı değişikliklerin olaylar tarafından PropertyChanged tetiklenmesi de mümkündür. Basamaklı değişiklikler genellikle, basamaklı değişikliğin yürütülmesi güvenli olmadan önce güncelleştirmelerin tamamlanmasını gerektirir.
  • Özellik değişmezse hiçbir zaman olay PropertyChanged oluşturmaz. Bu, olayı oluşturmadan PropertyChanged önce eski ve yeni değerleri karşılaştırmanız gerektiği anlamına gelir.
  • Bir özelliği başlatıyorsanız PropertyChanged hiçbir zaman görünüm modelinin oluşturucusunun sırasında olayı yükseltmeyin. Görünümdeki veriye bağlı denetimler bu noktada değişiklik bildirimleri almak için abone olmayacaktır.
  • Bir sınıfın ortak yönteminin tek bir zaman uyumlu çağrısı içinde hiçbir zaman aynı özellik adı bağımsız değişkenine sahip birden PropertyChanged fazla olay oluşturmaz. Örneğin, yedekleme deposu _numberOfItems alan olan bir NumberOfItems özellik verildiğinde, bir yöntem döngünün yürütülmesi sırasında elli kat artarsa_numberOfItems, tüm çalışma tamamlandıktan sonra özellikte NumberOfItems yalnızca bir kez özellik değişikliği bildirimi tetiklemelidir. Zaman uyumsuz yöntemler için, zaman uyumsuz bir devamlılık zincirinin PropertyChanged her zaman uyumlu kesiminde belirli bir özellik adı için olayı tetikleyin.

eShopOnContainers mobil uygulaması, aşağıdaki kod örneğinde gösterilen değişiklik bildirimlerini sağlamak için sınıfını kullanır ExtendedBindableObject :

public abstract class ExtendedBindableObject : BindableObject  
{  
    public void RaisePropertyChanged<T>(Expression<Func<T>> property)  
    {  
        var name = GetMemberInfo(property).Name;  
        OnPropertyChanged(name);  
    }  

    private MemberInfo GetMemberInfo(Expression expression)  
    {  
        ...  
    }  
}

Xamarin.Form'un BindableObject sınıfı arabirimini INotifyPropertyChanged uygular ve bir OnPropertyChanged yöntem sağlar. sınıfı ExtendedBindableObject , özellik değişikliği bildirimini çağırmak için yöntemini sağlar RaisePropertyChanged ve bunu yaparken sınıfı tarafından BindableObject sağlanan işlevselliği kullanır.

eShopOnContainers mobil uygulamasındaki her görünüm modeli sınıfı sınıfından ViewModelBase türetilir ve bu da sınıfından ExtendedBindableObject türetilir. Bu nedenle, her görünüm modeli sınıfı, özellik değişikliği bildirimi sağlamak için sınıfındaki ExtendedBindableObject yöntemini kullanırRaisePropertyChanged. Aşağıdaki kod örneği, eShopOnContainers mobil uygulamasının lambda ifadesi kullanarak özellik değişikliği bildirimini nasıl çağırdığını gösterir:

public bool IsLogin  
{  
    get  
    {  
        return _isLogin;  
    }  
    set  
    {  
        _isLogin = value;  
        RaisePropertyChanged(() => IsLogin);  
    }  
}

Lambda ifadesinin bu şekilde kullanılmasının küçük bir performans maliyeti içerdiğini unutmayın çünkü lambda ifadesinin her çağrı için değerlendirilmesi gerekir. Performans maliyeti küçük olsa ve normalde bir uygulamayı etkilemese de, birçok değişiklik bildirimi olduğunda maliyetler tahakkuk edebilir. Ancak bu yaklaşımın avantajı, özellikleri yeniden adlandırırken derleme zamanı türü güvenliği ve yeniden düzenleme desteği sağlamasıdır.

Komutları ve Davranışları Kullanarak Kullanıcı Arabirimi Etkileşimi

Mobil uygulamalarda, eylemler genellikle arka planda kod dosyasında bir olay işleyicisi oluşturularak uygulanabilen düğme tıklaması gibi bir kullanıcı eylemine yanıt olarak çağrılır. Ancak MVVM düzeninde eylemi uygulama sorumluluğu görünüm modeline aittir ve arka planda kod yerleştirmekten kaçınılmalıdır.

Komutlar, kullanıcı arabirimindeki denetimlere bağlanabilen eylemleri göstermek için kullanışlı bir yol sağlar. Eylemi uygulayan kodu kapsüller ve görünümdeki görsel gösteriminden ayrı tutmaya yardımcı olur. Xamarin.Forms , bir komuta bildirim temelli olarak bağlanabilen denetimler içerir ve kullanıcı denetimle etkileşime geçtiğinde bu denetimler komutu çağırır.

Davranışlar, denetimlerin bir komuta bildirim temelli olarak bağlanmasına da olanak sağlar. Ancak davranışlar, bir denetim tarafından tetiklenen bir dizi olayla ilişkili bir eylemi çağırmak için kullanılabilir. Bu nedenle davranışlar, daha fazla esneklik ve denetim sağlarken, komut etkin denetimlerle aynı senaryoların çoğunu ele alır. Ayrıca davranışlar, komutlarla etkileşime geçmek için özel olarak tasarlanmamış denetimlerle komut nesnelerini veya yöntemlerini ilişkilendirmek için de kullanılabilir.

Komutları Uygulama

Görünüm modelleri genellikle görünümden bağlama için arabirimi uygulayan ICommand nesne örnekleri olan komut özelliklerini kullanıma sunar. Bir dizi Xamarin.Forms denetim, görünüm modeli tarafından sağlanan bir nesneye bağlı veriler olabilecek bir ICommand özellik sağlarCommand. Arabirim ICommand , işlemin kendisini kapsülleyen bir Execute yöntemi, komutun çağrılıp çağrılamayacağını belirten bir CanExecute yöntemi ve komutun yürütülip yürütülmeyeceğini etkileyen değişiklikler gerçekleştiğinde oluşan bir CanExecuteChanged olayı tanımlar. Command tarafından Xamarin.Formssağlanan ve Command<T> sınıfları, ve CanExecutebağımsız değişkenlerinin Execute türü olan T arabirimini uygularICommand.

Görünüm modelinde, türündeki Command görünüm modelindeki her ortak özellik için veya Command<T> türünde ICommandbir nesne olmalıdır. Command veya Command<T> oluşturucu, yöntem çağrıldığında ICommand.Execute çağrılan bir Action geri çağırma nesnesi gerektirir. CanExecute yöntemi isteğe bağlı bir oluşturucu parametresidir ve döndüren bir boolparametresidirFunc.

Aşağıdaki kodda, bir yazmaç komutunu temsil eden örneğin Command , görünüm modeli yöntemi için Register bir temsilci belirtilerek nasıl oluşturulduğu gösterilmektedir:

public ICommand RegisterCommand => new Command(Register);

komutu, bir öğesine başvuru döndüren bir özellik aracılığıyla görünüme ICommandsunulur. Execute yöntemi nesnesinde Command çağrıldığında, çağrıyı oluşturucuda belirtilen temsilci aracılığıyla görünüm modelindeki yöntemine Command iletir.

Zaman uyumsuz bir yöntem, komutun temsilcisi belirtilirken ve await anahtar sözcükleri kullanılarak async bir komut Execute tarafından çağrılabilir. Bu, geri çağırmanın bir Task olduğunu ve beklenmesi gerektiğini gösterir. Örneğin, aşağıdaki kod, bir oturum açma komutunu temsil eden örneğin Command , görünüm modeli yöntemi için bir temsilci belirterek nasıl oluşturulduğu gösterir SignInAsync :

public ICommand SignInCommand => new Command(async () => await SignInAsync());

Komutun örneğini Execute oluştururken sınıfı kullanılarak Command<T> ve CanExecute eylemlerine parametreler geçirilebilir. Örneğin, aşağıdaki kod, yönteminin türünde stringbir bağımsız değişken gerektireceğini NavigateAsync belirtmek için örneğin Command<T> nasıl kullanıldığını gösterir:

public ICommand NavigateCommand => new Command<string>(NavigateAsync);

Hem hem Command<T> de sınıflarındaCommand, her oluşturucudaki yöntemin CanExecute temsilcisi isteğe bağlıdır. Bir temsilci belirtilmezse, Command için CanExecutedöndürürtrue. Ancak görünüm modeli, nesnesinin yöntemini Command çağırarak komutun CanExecuteChangeCanExecute durumunda bir değişiklik olduğunu gösterebilir. Bu, olayın yükseltilmesine neden olur CanExecuteChanged . Kullanıcı arabirimindeki komuta bağlı tüm denetimler, etkin durumlarını veriye bağlı komutun kullanılabilirliğini yansıtacak şekilde güncelleştirir.

Görünümden Komut Çağırma

Aşağıdaki kod örneği, içindeki öğesinin GridLoginView bir örneği kullanarak TapGestureRecognizer sınıfına nasıl bağlandığını LoginViewModelRegisterCommand gösterir:

<Grid Grid.Column="1" HorizontalOptions="Center">  
    <Label Text="REGISTER" TextColor="Gray"/>  
    <Grid.GestureRecognizers>  
        <TapGestureRecognizer Command="{Binding RegisterCommand}" NumberOfTapsRequired="1" />  
    </Grid.GestureRecognizers>  
</Grid>

Komut parametresi isteğe bağlı olarak özelliği kullanılarak CommandParameter da tanımlanabilir. Beklenen bağımsız değişkenin türü ve CanExecute hedef yöntemlerinde Execute belirtilir. kullanıcı TapGestureRecognizer ekli denetimle etkileşime geçtiğinde hedef komutu otomatik olarak çağırır. Komut parametresi sağlanırsa, komutun Execute temsilcisine bağımsız değişken olarak geçirilir.

Davranışları Uygulama

Davranışlar, alt sınıfa almak zorunda kalmadan kullanıcı arabirimi denetimlerine işlevsellik eklenmesine olanak sağlar. Bunun yerine, işlev bir davranış sınıfında uygulanır ve denetimin bir parçasıymış gibi denetime eklenir. Davranışlar, denetimin API'siyle doğrudan etkileşim kurarak denetime kısa bir şekilde eklenebileceği ve birden fazla görünüm veya uygulamada yeniden kullanılmak üzere paketlenebileceği için normalde arka planda kod yazmanız gereken kodu uygulamanızı sağlar. MVVM bağlamında, davranışlar denetimleri komutlara bağlamak için yararlı bir yaklaşımdır.

Ekli özellikler aracılığıyla bir denetime eklenen davranış, ekli davranış olarak bilinir. Daha sonra davranış, görünümün görsel ağacında söz konusu denetime veya diğer denetimlere işlevsellik eklemek için eklendiği öğenin kullanıma sunulan API'sini kullanabilir. eShopOnContainers mobil uygulaması, ekli bir davranış olan sınıfını içerir LineColorBehavior . Bu davranış hakkında daha fazla bilgi için bkz . Doğrulama Hatalarını Görüntüleme.

DavranışXamarin.Forms, veya Behavior<T> sınıfından Behavior türetilen bir sınıftır; buradaT, davranışın uygulanması gereken denetimin türüdür. Bu sınıflar, davranış denetimlere eklendiğinde ve OnDetachingFrom denetimlerden ayrıldığında yürütülecek mantığı sağlamak için geçersiz kılınması gereken ve yöntemlerini sağlarOnAttachedTo.

eShopOnContainers mobil uygulamasında sınıfı sınıfından BindableBehavior<T>Behavior<T> türetilir. sınıfının amacı, davranışın BindableBehavior<T> ekli denetime ayarlanmasını gerektiren BindingContext davranışlar için Xamarin.Forms bir temel sınıf sağlamaktır.

sınıfı, BindableBehavior<T> davranışını ayarlayan BindingContext geçersiz kılınabilir OnAttachedTo bir yöntem ve öğesini temizleyen BindingContextgeçersiz kılınabilir OnDetachingFrom bir yöntem sağlar. Ayrıca, sınıfı özelliğinde AssociatedObject ekli denetime bir başvuru depolar.

eShopOnContainers mobil uygulaması, gerçekleşen bir EventToCommandBehavior olaya yanıt olarak bir komut yürüten bir sınıf içerir. Bu sınıf sınıfından BindableBehavior<T> türetilir, böylece davranış kullanıldığında davranış bir özellik tarafından belirtilen bir ICommandCommand özelliğe bağlanabilir ve yürütebilir. Aşağıdaki kod örneği sınıfını EventToCommandBehavior gösterir:

public class EventToCommandBehavior : BindableBehavior<View>  
{  
    ...  
    protected override void OnAttachedTo(View visualElement)  
    {  
        base.OnAttachedTo(visualElement);  

        var events = AssociatedObject.GetType().GetRuntimeEvents().ToArray();  
        if (events.Any())  
        {  
            _eventInfo = events.FirstOrDefault(e => e.Name == EventName);  
            if (_eventInfo == null)  
                throw new ArgumentException(string.Format(  
                        "EventToCommand: Can't find any event named '{0}' on attached type",   
                        EventName));  

            AddEventHandler(_eventInfo, AssociatedObject, OnFired);  
        }  
    }  

    protected override void OnDetachingFrom(View view)  
    {  
        if (_handler != null)  
            _eventInfo.RemoveEventHandler(AssociatedObject, _handler);  

        base.OnDetachingFrom(view);  
    }  

    private void AddEventHandler(  
            EventInfo eventInfo, object item, Action<object, EventArgs> action)  
    {  
        ...  
    }  

    private void OnFired(object sender, EventArgs eventArgs)  
    {  
        ...  
    }  
}

OnAttachedTo ve OnDetachingFrom yöntemleri, özelliğinde EventName tanımlanan olay için bir olay işleyicisini kaydetmek ve kaydını silmek için kullanılır. Ardından, olay tetiklendiğinde OnFired komutunu yürüten yöntemi çağrılır.

Bir olay tetiklendiğinde komutunu yürütmek için komutunu kullanmanın EventToCommandBehavior avantajı, komutların komutlarla etkileşime geçmek için tasarlanmamış denetimlerle ilişkilendirilebileceğidir. Buna ek olarak, olay işleme kodu modelleri görüntülemek için taşınır ve burada birim test edilebilir.

Görünümden Davranışları Çağırma

EventToCommandBehavior, komutları desteklemeyen bir denetime komut eklemek için özellikle yararlıdır. Örneğin, aşağıdaki kodda ProfileView gösterildiği gibi, kullanıcının siparişlerini listeleyen olay tetiklendiğinde ListViewItemTapped öğesini yürütmek OrderDetailCommand için kullanırEventToCommandBehavior:

<ListView>  
    <ListView.Behaviors>  
        <behaviors:EventToCommandBehavior             
            EventName="ItemTapped"  
            Command="{Binding OrderDetailCommand}"  
            EventArgsConverter="{StaticResource ItemTappedEventArgsConverter}" />  
    </ListView.Behaviors>  
    ...  
</ListView>

çalışma zamanında ile EventToCommandBehavior etkileşime ListViewyanıt verir. içinde ListViewItemTapped bir öğe seçildiğinde, olayı tetiklenir ve içinde öğesini OrderDetailCommandProfileViewModelyürütür. Varsayılan olarak, olayın olay bağımsız değişkenleri komutuna geçirilir. Bu veriler, özelliğinde EventArgsConverter belirtilen dönüştürücü tarafından kaynak ve hedef arasında geçirildikçe dönüştürülür ve bu da ItemListView öğesinin ItemTappedEventArgsdeğerini döndürür. Bu nedenle, yürütülürken OrderDetailCommand , seçilen Order kayıtlı Eylem parametresi olarak geçirilir.

Davranışlar hakkında daha fazla bilgi için bkz . Davranışlar.

Özet

Model-View-ViewModel (MVVM) deseni, bir uygulamanın iş ve sunu mantığını kullanıcı arabiriminden (UI) temiz bir şekilde ayırmaya yardımcı olur. Uygulama mantığı ve kullanıcı arabirimi arasında temiz bir ayrım yapılması, çok sayıda geliştirme sorununun giderilmesine yardımcı olur ve uygulamanın testini, bakımını yapmasını ve gelişmesini kolaylaştırabilir. Ayrıca kod yeniden kullanım fırsatlarını büyük ölçüde geliştirebilir ve geliştiricilerin ve kullanıcı arabirimi tasarımcılarının bir uygulamanın ilgili bölümlerini geliştirirken daha kolay işbirliği yapmasına olanak tanır.

MVVM deseni kullanılarak uygulamanın kullanıcı arabirimi ile temel alınan sunu ve iş mantığı üç ayrı sınıfa ayrılır: kullanıcı arabirimini ve kullanıcı arabirimi mantığını kapsülleyen görünüm; sunu mantığını ve durumunu kapsülleyen görünüm modeli; ve uygulamanın iş mantığını ve verilerini kapsülleyen model.