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.
Ş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 ListView
gibi 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 BindingContext
olarak 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 AutoWireViewModel
vardı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ınPropertyChanged
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ındanPropertyChanged
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şturmadanPropertyChanged
ö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 birNumberOfItems
ö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 özellikteNumberOfItems
yalnızca bir kez özellik değişikliği bildirimi tetiklemelidir. Zaman uyumsuz yöntemler için, zaman uyumsuz bir devamlılık zincirininPropertyChanged
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 CanExecute
bağı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 ICommand
bir 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 bool
parametresidirFunc
.
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 ICommand
sunulur. 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 string
bir 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 CanExecute
döndürürtrue
. Ancak görünüm modeli, nesnesinin yöntemini Command
çağırarak komutun CanExecute
ChangeCanExecute
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 Grid
LoginView
bir örneği kullanarak TapGestureRecognizer
sınıfına nasıl bağlandığını LoginViewModel
RegisterCommand
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 BindingContext
geç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 ICommand
Command
ö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 ListView
ItemTapped
öğ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 ListView
yanıt verir. içinde ListView
ItemTapped
bir öğe seçildiğinde, olayı tetiklenir ve içinde öğesini OrderDetailCommand
ProfileViewModel
yü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 Item
ListView
öğesinin ItemTappedEventArgs
değ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.