MVVM, zayıf tasarlanmış veri bağlama katmanları için bir bant yardımcısıdır. Özellikle WPF / silverlight / WP7 dünyasında, WPF / XAML'deki veri bağlanmasındaki kısıtlamalar nedeniyle çok fazla kullanım görmüştür.
Şu andan itibaren, WPF / XAML hakkında konuştuğumuzu farz edeceğim, çünkü bu her şeyi daha net hale getirecek. MVVM'nin WPF / XAML'de çözmek için belirlediği bazı eksikliklere bakalım.
Veri şekli vs UI şekli
MVVM'deki 'VM', C # 'da tanımlanan ve XAML'de tanımlanan bir dizi sunum nesnesiyle eşlenen bir nesne kümesi oluşturur. Bu C # nesneleri tipik olarak sunum nesnelerindeki DataContext özellikleriyle XAML'ye bağlanır.
Sonuç olarak, viewmodel nesne grafiğinin uygulamanızın sunum nesnesi grafiğiyle eşleşmesi gerekir. Bu, eşleştirmenin birebir olması gerektiğini söylemez, ancak bir liste denetimi bir pencere denetimi içeriyorsa, pencerenin DataContext nesnesinden o listenin verilerini tanımlayan bir nesneye ulaşmanın bir yolu olmalıdır.
Viewmodel nesne grafiği, model nesne grafiğini kullanıcı arabirimi grafik grafiğinden başarıyla ayırır, ancak inşa edilmesi ve bakımı gereken ek bir görünüm modeli katmanı pahasına.
Bazı verileri ekran A'dan ekran B'ye taşımak istersem, görünüm modelleriyle uğraşmam gerekir. Bir iş adamı aklında, bu bir UI değişikliğidir. Bu olmalıdır XAML dünyasında tamamen gerçekleşecek. Ne yazık ki, nadiren olabilir. Daha da kötüsü, görünüm modellerinin nasıl yapılandırıldığına ve verilerin aktif olarak nasıl değiştiğine bağlı olarak, bu değişikliği gerçekleştirmek için oldukça fazla veri yönlendirmesi gerekebilir.
Anlatımsal veri bağlamada çalışmak
WPF / XAML bağlayıcıları yeterince anlamlı değil. Temel olarak bir nesneye ulaşmanın bir yolunu, çaprazlanacak bir özellik yolunu ve data özelliğinin değerini sunum nesnesinin gerektirdiği şekilde uyarlamak için bağlayıcıları sağlarsınız.
C # 'daki bir mülkü ondan daha karmaşık bir şeye bağlamanız gerekiyorsa, temel olarak şansınız kalmaz. Ben doğru / yanlış Görünür / Daralt dönüştürülmüş bir bağlayıcı dönüştürücü olmadan bir WPF uygulaması görmedim. Birçok WPF uygulaması ayrıca, Polarating'i çeviren NegatingVisibilityConverter veya benzeri bir şeye sahip olma eğilimindedir. Bu alarm zilleri çalıyor olmalı.
MVVM, bu sınırlamayı aşmak için kullanılabilecek C # kodunuzu yapılandırmak için size rehberlik eder. Görünüm modelinizde SomeButtonVisibility adlı bir özelliği gösterebilir ve bu düğmenin görünürlüğüne bağlayabilirsiniz. XAML'iniz şimdi hoş ve güzel ... ama kendinizi bir tezgahtar haline getirdiniz - şimdi kullanıcı arabiriminiz gelişirken iki yerde (UI ve C # kodundaki) bağlantıları göstermeniz ve güncellemeniz gerekiyor. Aynı düğmeye başka bir ekranda olmak için ihtiyaç duyuyorsanız, benzer bir özelliği bir görünüm modelinde o ekranın erişebileceği şekilde göstermeniz gerekir. Daha da kötüsü, sadece XAML'a bakamıyorum ve düğmenin artık ne zaman görünür olacağını göremiyorum. Ciltlemeler biraz önemsiz hale gelir gelmez, C # kodunda dedektiflik yapmam gerekiyor.
Verilere erişim agresif bir şekilde kapsamlıdır
Veriler genellikle UI'ya DataContext özellikleriyle girdiğinden, uygulamanız boyunca tutarlı şekilde genel veya oturum verilerini temsil etmek zordur.
"Şu anda oturum açan kullanıcı" fikri harika bir örnektir - bu genellikle uygulamanızın bir örneğinde gerçekten genel bir şeydir. WPF / XAML'de mevcut kullanıcıya tutarlı bir şekilde global erişim sağlamak çok zor.
Yapmak istediğim, şu anda oturum açan kullanıcıya atıfta bulunmak için veri bağlantılarında "CurrentUser" kelimesini özgürce kullanmak. Bunun yerine, her DataContext'in bana geçerli kullanıcı nesnesine ulaşmak için bir yol sağladığından emin olmalıyım . MVVM bunu başarabilir, ancak hepsi bu küresel verilere erişim sağlamak zorunda kaldıklarından, görünüm modları karışıklık yaratacak.
MVVM'nin düştüğü bir örnek
Diyelim ki bir kullanıcı listemiz var. Her kullanıcının yanında, "kullanıcıyı sil" düğmesini görüntülemek istiyoruz, ancak yalnızca oturum açmış kullanıcı bir yönetici ise. Ayrıca, kullanıcıların kendilerini silmelerine izin verilmez.
Model nesneleriniz şu anda oturum açmış olan kullanıcı hakkında bir şey bilmemelidir - yalnızca veritabanınızdaki kullanıcı kayıtlarını temsil ederler, ancak bir şekilde şu anda oturum açmış kullanıcının liste satırlarınızdaki veri bağlantılarına maruz kalması gerekir. MVVM, oturum açmış olan kullanıcıyı o liste satırının temsil ettiği kullanıcı ile birleştiren her liste satırı için bir görünüm modeli nesnesi oluşturmamızı, ardından bu görünüm modeli nesnesine (duygularınıza bağlı olarak "DeleteButtonVisibility" veya "CanDelete" adı verilen bir özellik göstermemizi istiyor. bağlayıcı dönüştürücüler hakkında).
Bu nesne, bir Kullanıcı nesnesi gibi diğer birçok yolla berbat bir şekilde görünecek - tüm kullanıcı modeli nesnesinin özelliklerini yansıtması ve bu veriler değiştikçe güncellemeleri iletmesi gerekebilir. Bu gerçekten çok acayip hissediyor - yine, MVVM sizi bu kullanıcı-çalışma nesnesini korumaya zorlayarak sizi bir katip yapıyor.
Bir düşünün - muhtemelen kullanıcılarınızın özelliklerini bir veritabanında, modelde ve görünümde temsil etmeniz gerekir. Siz ve veritabanınız arasında bir API varsa, daha da kötüsü - veritabanında, API sunucusunda, API istemcisinde, modelde ve görünümde temsil edilirler. Bir mülk her eklendiğinde ya da değiştirildiğinde, dokunulması gereken başka bir katman ekleyen bir tasarım deseni benimsemekte tereddütüm var.
Daha da kötüsü, bu katman veri modelinizin karmaşıklığı ile değil, kullanıcı arayüzünüzün karmaşıklığı ile ölçeklenir. Genellikle, aynı veriler birçok yerde ve kullanıcı arayüzünüzde temsil edilir - bu yalnızca bir katman eklemekle kalmaz, çok fazla yüzey alanı olan bir katman ekler!
İşler nasıl olabilirdi
Yukarıda açıklanan durumda şunu söylemek isterim:
<Button Visibility="{CurrentUser.IsAdmin && CurrentUser.Id != Id}" ... />
CurrentUser benim uygulamamdaki tüm XAML'ye global olarak maruz kalacaktı. Id, liste satırım için DataContext'teki bir özelliğe başvurur. Görünürlük, booleandan otomatik olarak dönüştürülecekti. Id, CurrentUser.IsAdmin, CurrentUser veya CurrentUser.Id güncellemeleri bu düğmenin görünürlüğünde bir güncelleme tetikler. Tereyağından kıl çeker gibi.
Bunun yerine, WPF / XAML, kullanıcılarını tam bir karışıklık yaratmaya zorlar. Söyleyebileceğim kadarıyla, bazı yaratıcı blogcular bu karışıklığa bir isim tokatladı ve bu isim MVVM idi. Kanmayın - GoF tasarım desenleri ile aynı sınıfta değil. Bu çirkin bir veri bağlama sistemi etrafında çalışmak için çirkin bir keskidir.
(Bu yaklaşım, daha fazla okumaya devam etmeniz durumunda bazen "Fonksiyonel Reaktif Programlama" olarak adlandırılır).
Sonuç olarak
WPF / XAML'de çalışmanız gerekiyorsa, hala MVVM'yi önermiyorum.
Kodunuzun, yukarıdaki “örneklerin nasıl olmuş olabileceği” örneğinde olduğu gibi yapılandırılmasını istiyorsunuz; bu, karmaşık veri bağlama ifadeleri + esnek değer zorlamaları ile doğrudan görüntülemeye açık bir model. Bu daha iyi - daha okunaklı, daha yazılabilir ve daha fazla bakım yapılabilir.
MVVM, kodunuzu daha ayrıntılı, daha az bakım gerektirmeyen bir şekilde yapılandırmanızı söyler.
MVVM yerine, iyi bir deneyime yaklaşmanıza yardımcı olacak bazı şeyler oluşturun: Global durumu sürekli olarak UI'nıza göstermek için bir kongre hazırlayın. Kendinizi daha karmaşık ciltleme ifadeleri ifade etmenizi sağlayan ciltleme dönüştürücüleri, Çoklu Ciltleme vb. Yaygın zorlama vakalarını daha az acı verici hale getirmek için kendinize bir bağlayıcı dönüştürücü kitaplığı oluşturun.
Daha da iyisi - XAML'yi daha anlamlı bir şeyle değiştirin. XAML, C # nesnelerini somutlaştırmak için çok basit bir XML formatıdır - daha etkileyici bir değişken bulmak zor olmaz.
Diğer tavsiyem: bu tür uzlaşmalara zorlayan araçlar kullanmayın. Sorun alanınıza odaklanmak yerine, sizi MVVM gibi boka doğru iterek nihai ürününüzün kalitesine zarar vereceklerdir.