Model-Görünüm-GörünümModeli (MVVM)
İpucu
Bu içerik, .NET Docs'ta veya çevrimdışı olarak okunabilen ücretsiz indirilebilir bir PDF olarak bulunan .NET MAUIKullanan Kurumsal Uygulama Desenleri adlı e-Kitap'tan bir alıntıdır.
.NET MAUI 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.
MVVM düzeni, 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 sağlamak, çok sayıda geliştirme sorununun giderilmesine yardımcı olur ve uygulamanın testini, bakımını ve gelişmesini kolaylaştırır. Ayrıca kod yeniden kullanım fırsatlarını önemli ö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
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. Aşağıdaki diyagramda üç bileşen arasındaki ilişkiler gösterilmektedir.
Her bileşenin sorumluluklarını anlamanın yanı sıra, 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 bir model uygulaması mevcut iş mantığını kapsüllerse, 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 yapmanızı engeller.
- 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 veya C# dilinde uygulanması koşuluyla, uygulama kullanıcı arabirimi görünüm modeline ve model koduna 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ımcılar ve geliştiriciler geliştirme sırasında bileşenleri üzerinde bağımsız ve eşzamanlı olarak çalışabilir. Tasarımcılar 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ı 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.
Bir .NET MAUI uygulamasında görünüm genellikle ContentPage
-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ğine 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 oluşturulacak olayı dinleyebilir. Yanıt olarak, davranış daha sonra görünüm modelinde bir ICommand veya 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.
Çok platformlu 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 daha kolay görüntülenmesini sağlayabilir.
İ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ğlama
Görünüm modelleri, .NET'in MAUIveri bağlama özellikleri kullanılarak görünümlere bağ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ı, Microsoft Maui'nin gezinme sırasında sayfaları oluşturan gezinme sistemiyle uyumludur, bu da görünüm modelinin ilk bileşimini karmaşık hale getirir ve platformla uyumlu değildir.
Görünüm modelinin ilk bileşimiyle, uygulama kavramsal olarak görünüm modellerinden oluşur ve görünüm modelinin görünümünü bulmakla sorumlu bir hizmettir. 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 Button ve ListView gibi 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>
<!-- Omitted for brevity... -->
</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çlanır. 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.
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.
Uygulama, 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 deposuNumberOfItems
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 ö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.
Bu işlevi sağlamanın basit bir yolu, sınıfının bir uzantısını BindableObject
oluşturmaktır. Bu örnekte sınıfı, ExtendedBindableObject
aşağıdaki kod örneğinde gösterilen değişiklik bildirimleri sağlar:
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)
{
// Omitted for brevity ...
}
}
.NET'in MAUIBindableObject
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.
Görünüm modeli sınıfları daha sonra sınıfından ExtendedBindableObject
türetilebilir. 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 RaisePropertyChanged
yöntemini kullanırExtendedBindableObject
. Aşağıdaki kod örneği, eShop çok platformlu uygulamasının lambda ifadesi kullanarak özellik değişikliği bildirimini nasıl çağırdığı gösterilmektedir:
public bool IsLogin
{
get => _isLogin;
set
{
_isLogin = value;
RaisePropertyChanged(() => IsLogin);
}
}
Lambda ifadesinin bu şekilde kullanılması küçük bir performans maliyeti gerektirir çünkü lambda ifadesinin her çağrı için değerlendirilmesi gerekir. Performans maliyeti küçük olsa ve genellikle 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.
MVVM Çerçeveleri
MVVM düzeni .NET'te iyi oluşturulmuştur ve topluluk bu geliştirmeyi kolaylaştıracak birçok çerçeve oluşturmuştur. Her çerçeve farklı bir özellik kümesi sağlar, ancak arabirimin uygulanmasıyla INotifyPropertyChanged
ortak bir görünüm modeli sağlamaları standarttır. MVVM çerçevelerinin ek özellikleri arasında özel komutlar, gezinti yardımcıları, bağımlılık ekleme/hizmet bulucu bileşenleri ve kullanıcı arabirimi platformu tümleştirmesi yer alır. Bu çerçeveleri kullanmak gerekli olmasa da geliştirmenizi hızlandırabilir ve standartlaştırabilir. eShop çok platformlu uygulaması .NET Community MVVM Araç Seti'ni kullanır. Çerçeve seçerken uygulamanızın gereksinimlerini ve ekibinizin güçlü yönlerini dikkate almanız gerekir. Aşağıdaki liste .NET MAUIiçin daha yaygın MVVM çerçevelerinden bazılarını içerir.
Komutları ve davranışları kullanarak kullanıcı arabirimi etkileşimi
Çok platformlu 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. Bu şekilde, görünüm modelleriniz platform kullanıcı arabirimi çerçevesi tarafından sağlanan olaylara doğrudan bağımlı olmadığından yeni platformlara daha taşınabilir hale gelir. .NET MAUI , 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 arabirimi uygulayan ICommand
görünümden bağlama için genel özellikleri kullanıma sunar. Birçok .NET MAUI denetimi ve hareketi, görünüm modeli tarafından sağlanan bir nesneye bağlı veriler olabilecek bir Command
özellik sağlarICommand
. Düğme denetimi, en sık kullanılan denetimlerden biridir ve düğmeye tıklandığında yürütülen bir komut özelliği sağlar.
Not
Görünüm modelinizin kullandığı arabirimin ICommand
gerçek uygulamasını (örneğin, veya Command<T>
) kullanıma sunmanız mümkün olsa da komutlarınızı RelayCommand
genel olarak olarak ICommand
olarak kullanıma sunmanız önerilir. Bu şekilde, uygulamayı daha sonraki bir tarihte değiştirmeniz gerekirse kolayca değiştirilebilir.
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. Çoğu durumda yalnızca komutlarımız için yöntemini sağlarız Execute
. daha ayrıntılı bir genel bakış ICommand
için .NET için Komut belgelerineMAUI.
.NET MAUI ile sağlanan, Command
ve Command<T>
için bağımsız değişkenlerin ICommand
türü olan T
arabirimi uygulayan Execute
ve CanExecute
sınıflarıdır.
Command
ve Command<T>
arabirim için gereken en düşük işlevsellik kümesini sağlayan temel uygulamalardır ICommand
.
Not
Birçok MVVM çerçevesi, arabirimin ICommand
daha fazla özellik zengin uygulaması sunar.
Command
veya Command<T>
oluşturucu, yöntem çağrıldığında ICommand.Execute
çağrılan bir Eylem geri çağırma nesnesi gerektirir.
CanExecute
yöntemi isteğe bağlı bir oluşturucu parametresidir ve bool döndüren bir Func'dir.
eShop çok platformlu uygulaması RelayCommand ve AsyncRelayCommand'ı kullanır. Modern uygulamaların birincil avantajı, zaman uyumsuz işlemler için daha iyi işlevsellik sağlamasıdır AsyncRelayCommand
.
Aşağıdaki kod, bir yazmaç komutunu temsil eden örneğin Command
, Register görünüm modeli yöntemi için bir temsilci belirterek nasıl oluşturulduğu gösterir:
public ICommand RegisterCommand { get; }
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 zaman uyumsuz ve await anahtar sözcükleri kullanılarak 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 ICommand
, görünüm modeli yöntemi için bir temsilci belirtilerek nasıl oluşturulduğunı SignInAsync
gösterir:
public ICommand SignInCommand { get; }
...
SignInCommand = new AsyncRelayCommand(async () => await SignInAsync());
Komutun örneğini Execute
oluştururken sınıfı kullanılarak CanExecute
ve AsyncRelayCommand<T>
eylemlerine parametreler geçirilebilir. Örneğin, aşağıdaki kod, yöntemin dize türünde bir bağımsız değişken gerektireceğini belirtmek AsyncRelayCommand<T>
için örneğin NavigateAsync
nasıl kullanıldığını gösterir:
public ICommand NavigateCommand { get; }
...
NavigateCommand = new AsyncRelayCommand<string>(NavigateAsync);
Hem hem RelayCommand
de sınıflarındaRelayCommand<T>
, her oluşturucudaki yöntemin CanExecute
temsilcisi isteğe bağlıdır. Bir temsilci belirtilmezse, Command
için CanExecute
true değerini döndürür. Ancak görünüm modeli, nesnesinin yöntemini CanExecute
çağırarak komutun ChangeCanExecute
Command
durumunda bir değişiklik olduğunu gösterebilir. Bu, olayın yükseltilmesine neden olur CanExecuteChanged
. Ardından komuta bağlı tüm kullanıcı arabirimi denetimleri, etkin durumlarını veriye bağlı komutun kullanılabilirliğini yansıtacak şekilde güncelleştirir.
Görünümden komutları çağırma
Aşağıdaki kod örneği, içindeki öğesinin Grid
LoginView
bir örneği kullanarak RegisterCommand
sınıfına nasıl bağlandığını LoginViewModel
TapGestureRecognizer
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 Execute
hedef yöntemlerinde CanExecute
belirtilir. kullanıcı TapGestureRecognizer
ekli denetimle etkileşime geçtiğinde hedef komutu otomatik olarak çağırır.
CommandParameter
sağlanırsa, komutun Yürüt 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 eklenip birden fazla görünüm veya uygulamada yeniden kullanılmak üzere paketlenebileceği için genellikle 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.
.NET MAUI davranışı, veya Behavior
sınıfından Behavior<T>
türetilen bir sınıftır; burada T, davranışın uygulanacağı denetimin türüdür. Bu sınıflar, davranış denetimlere eklendiğinde ve OnAttachedTo
denetimlerden ayrıldığında yürütülecek mantığı sağlamak için geçersiz kılınması gereken ve yöntemlerini sağlarOnDetachingFrom
.
eShop çok platformlu uygulamasında, BindableBehavior<T>
sınıfı sınıfından Behavior<T>
türetilir. sınıfının amacı, davranışın BindableBehavior<T>
ekli denetime ayarlanmasını gerektiren MAUI .NET BindingContext
davranışları için bir temel sınıf sağlamaktır.
sınıfı, BindableBehavior<T>
davranışını ayarlayan OnAttachedTo
geçersiz kılınabilir BindingContext
bir yöntem ve öğesini temizleyen OnDetachingFrom
geçersiz kılınabilir BindingContext
bir yöntem sağlar.
eShop çok platformlu uygulaması, Community araç seti tarafından sağlanan bir MAUI sınıfı içerir.
EventToCommandBehavior
gerçekleşen bir olaya yanıt olarak bir komut yürütür. Bu sınıf sınıfından BaseBehavior<View>
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:
/// <summary>
/// The <see cref="EventToCommandBehavior"/> is a behavior that allows the user to invoke a <see cref="ICommand"/> through an event. It is designed to associate Commands to events exposed by controls that were not designed to support Commands. It allows you to map any arbitrary event on a control to a Command.
/// </summary>
public class EventToCommandBehavior : BaseBehavior<VisualElement>
{
// Omitted for brevity...
/// <inheritdoc/>
protected override void OnAttachedTo(VisualElement bindable)
{
base.OnAttachedTo(bindable);
RegisterEvent();
}
/// <inheritdoc/>
protected override void OnDetachingFrom(VisualElement bindable)
{
UnregisterEvent();
base.OnDetachingFrom(bindable);
}
static void OnEventNamePropertyChanged(BindableObject bindable, object oldValue, object newValue)
=> ((EventToCommandBehavior)bindable).RegisterEvent();
void RegisterEvent()
{
UnregisterEvent();
var eventName = EventName;
if (View is null || string.IsNullOrWhiteSpace(eventName))
{
return;
}
eventInfo = View.GetType()?.GetRuntimeEvent(eventName) ??
throw new ArgumentException($"{nameof(EventToCommandBehavior)}: Couldn't resolve the event.", nameof(EventName));
ArgumentNullException.ThrowIfNull(eventInfo.EventHandlerType);
ArgumentNullException.ThrowIfNull(eventHandlerMethodInfo);
eventHandler = eventHandlerMethodInfo.CreateDelegate(eventInfo.EventHandlerType, this) ??
throw new ArgumentException($"{nameof(EventToCommandBehavior)}: Couldn't create event handler.", nameof(EventName));
eventInfo.AddEventHandler(View, eventHandler);
}
void UnregisterEvent()
{
if (eventInfo is not null && eventHandler is not null)
{
eventInfo.RemoveEventHandler(View, eventHandler);
}
eventInfo = null;
eventHandler = null;
}
/// <summary>
/// Virtual method that executes when a Command is invoked
/// </summary>
/// <param name="sender"></param>
/// <param name="eventArgs"></param>
[Microsoft.Maui.Controls.Internals.Preserve(Conditional = true)]
protected virtual void OnTriggerHandled(object? sender = null, object? eventArgs = null)
{
var parameter = CommandParameter
?? EventArgsConverter?.Convert(eventArgs, typeof(object), null, null);
var command = Command;
if (command?.CanExecute(parameter) ?? false)
{
command.Execute(parameter);
}
}
}
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 OnTriggerHandled
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ış çağırma
EventToCommandBehavior
, komutları desteklemeyen bir denetime komut eklemek için özellikle yararlıdır. Örneğin LoginView, aşağıdaki kodda gösterildiği gibi kullanıcı parolasının değerini değiştirdiğinde öğesini yürütmek EventToCommandBehavior
için kullanırValidateCommand
:
<Entry
IsPassword="True"
Text="{Binding Password.Value, Mode=TwoWay}">
<!-- Omitted for brevity... -->
<Entry.Behaviors>
<mct:EventToCommandBehavior
EventName="TextChanged"
Command="{Binding ValidateCommand}" />
</Entry.Behaviors>
<!-- Omitted for brevity... -->
</Entry>
çalışma zamanında ile EventToCommandBehavior
etkileşime Entry
yanıt verir. Bir kullanıcı alana türediğinde Entry
, TextChanged
olayı tetiklenir ve içinde yürütülür ValidateCommand
LoginViewModel
. Varsayılan olarak, olayın olay bağımsız değişkenleri komutuna geçirilir. Gerekirse özelliği, EventArgsConverter
olay tarafından sağlanan değerini komutun giriş olarak beklediği bir değere dönüştürmek EventArgs
için kullanılabilir.
Davranışlar hakkında daha fazla bilgi için bkzMAUI.
Ö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 sağlamak, çok sayıda geliştirme sorununun giderilmesine yardımcı olur ve uygulamanın testini, bakımını ve gelişmesini kolaylaştırır. Ayrıca kod yeniden kullanım fırsatlarını önemli ö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.