Model-Görünüm-GörünümModeli (MVVM)

.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.

MVVM deseni

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'un Mauigezinti sırasında sayfa oluşturmakla sorumlu olan gezinti sistemiyle 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 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 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ç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ı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.

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 ExtendedBindableObject yöntemini kullanırRaisePropertyChanged. 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 ICommand özellik sağlarCommand. 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 RelayCommand) kullanıma sunmanız mümkün olsa da komutlarınızı Command<T> genel olarak olarak ICommandolarak 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ış ICommandiçin .NET MAUIiçin Komut belgelerine bakın.

.NET MAUI ile sağlanan, Command ve Command<T> için bağımsız değişkenlerin Execute türü olan T arabirimi uygulayan ICommand ve CanExecutesı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 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 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 AsyncRelayCommand<T> ve CanExecute 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 NavigateAsync için örneğin AsyncRelayCommand<T> nasıl kullanıldığını gösterir:

public ICommand NavigateCommand { get; }

...
NavigateCommand = new AsyncRelayCommand<string>(NavigateAsync);

Hem hem RelayCommand<T> de sınıflarındaRelayCommand, her oluşturucudaki yöntemin CanExecute temsilcisi isteğe bağlıdır. Bir temsilci belirtilmezse, Command için CanExecutetrue değerini döndürür. 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 . 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 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. CommandParametersağ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<T> sınıfından Behavior 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 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.

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 BindingContext .NET MAUI davranışları için 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.

eShop çok platformlu uygulaması, Community araç seti tarafından MAUI sağlanan bir EventToCommandBehavior 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 ValidateCommand için kullanırEventToCommandBehavior:

<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 Entryyanı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 bkz. .NET MAUI Geliştirici Merkezi'nin 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 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.