MVVM konusunda tonla İngilizce makale olmasına rağmen Türkçe içeriğin (her zaman ki gibi) eksik olması ve Türkiye'de bilinirliğini arttırmak amacıyla MVVM hakkında bir makale yazmayı düşünüyordum. .NET Framework teknolojileriyle ilgili yazılım geliştiricilere yönelik çıkması planlanlanan ancak çeşitli sebeplerden dolayı iptal edilen bir dergi için aylar önce yazdığım orijinal makalemi bu amaçla düzenleyerek - ve bir blog postu için uzun olduğu için bölerek - sizlerle paylaşıyorum.

1. WPF ile Model View ViewModel: Giriş
2. WPF ile MVVM: Model
3. WPF ile MVVM: View
4. WPF ile MVVM: ViewModel
5. WPF ile MVVM: Parçaları Birleştirmek
Seriye ait kaynak kodlar: MvvmWithWpfSample.rar (245,34 KB)

MVVM daha yenice bir mimari kalıp olduğu için, implementasyonunun nasıl olması gerektiği konusundaki tartışmalar halen devam etmektedir. Özellikle tartışılan ViewModel’in sorumluluklarının ne kadar olması gerektiği yanında, ViewModel’i View’ın DataContext’ine nasıl atanacağı karşımıza çıkar.
Bu konuda üç farklı yaklaşım mevcut:
  1. Önce View (View First) yaklaşımına göre, VM’in parametresiz inşa edici metodu View tarafından çağrılarak WPF tarafından inşa edilir. Bu yaklaşım için bir yol XAML’da ilgili VM’in gösterildiği bir DataContext elementi tanımlanması, bir diğer yol ise (örneğin UserControl için) View’ın DataContext’ine, hiyerarşik olarak daha yukarıdaki bir Vew’ın DataContext’inde bulunan ViewModel’in kullanılarak Bind edilmesidir. Bazıları Önce View yaklaşımı için code behind’a geçip el ile VM oluşturup DataContext’e atar, bu çok raifne bir yöntem olmasa da, VM’i manuel oluşturmak yerine, View’a bir IoC (Inversion of Control) konteynırı tarafından yapıcı metod enjeksiyonu ile VM vererek düzgün sonuçlar alınabilir. Ancak eğer özel IoC konteynırı uzantıları kullanmıyorsanız, enjeksiyonda verilen VM’in nasıl oluştuğu üzerinde kontrolünüz azalacaktır. VM’in yapıcı metodunun büyük ihtimalle parametresiz olması gerekecektir, ki bu da gerçek hayat senaryoları için çok kullanışlı olmayabilir.

  2. Önce ViewModel (ViewModel First) yaklaşımında da birden fazla yöntem vardır. VM oluşturulduktan sonra, yine bir IoC konteynırının vasıtasıyla belirlenmiş bir IView arayüzünü uygulamış nesne referansı alınır ve alınan bu referansın arayüzünde bulunan örneğin SetDataContext gibi bir metodu çağırarak, kendini parametre olarak geçer. Diğer bir yöntem ise “Typed DataTemplate” kullanmaktır. İlk olarak ResourceDictionary dosyasında ViewModel tipinin kullanacağı DataTemplate içinde View tipi deklare edilir. İkinci adımda View’da bulunan bir ItemsControl’un ItemSource özelliğine ViewModel’in kendisi Binding nesnesi olarak atanır. WPF, bağlı nesnelerin birinci adımda anlatıldığı gibi bir DataTemplate’e sahip olup olmadığını kontrol eder ve eğer mevcutsa bu nesnelerin ait olduğu View’ları varsayılan parametresiz inşa edici metodunu çağırarak oluşturur.

  3. Bazılarının Evlilik, bazılarının ise Controller şeklinde adlandırdığı son yaklaşımda, View ve VM dışında 3. bir bileşen, View ve VM’in örneğini alarak View’ın DataContext’ine VM’i atar. Biz demo uygulamamızda basitliği ve demomuz tek ekrandan meydana geldiği için bu yöntemi tercih ettik.


MVVM Hakkında Kısa İpuçları

  • ViewModel özelliklerine PropertyChanged event’i dışında başka metodları tetikleyecek kod yazmaktan kaçının. Bir senaryo için yapacaklarınız doğru iken, diğer senaryolarda VM özelliği tahmininiz dışında hareket ediyor olabilir.

  • Uygulamalarda çoğunlukla, Model’deki özellikleri VM üzerinde ayrı ayrı tanımlamak yerine, örneğin Customer gibi bir nesneyi VM’de tutmak ve bunun Name, Surname gibi özelliklerine de View’ın, Model üzerinden erişmesi tercih edilir. Böyle bir durumda model sınıfları INotifyPropertyChanged arayüzünü uygularlar ve model üzerinde yer alan koleksiyonlar da List, Set yerine ObservableCollection olmalıdır.

  • View ihtiyaçları yüzünden Model koleksiyonlarınızda kullandığınız Model sonıflarına “IsChecked” gibi alanlar ekliyorsanız, MVVM kalıbını bozuyorsunuz demektir. Bu tür özellikler tanımlamak yerine daha ayrıntılı VM’ler oluşturun.

Özet ve Bahsedilmeyenler

Makale serimizde WPF, MVVM’in temeli olan üç bileşen M-V

 

-VM
, aralarındaki ilişki, INotifyPropertyChanged, Command’lar gibi bir çok konuya değindik.

Konunun yeniliği sebebiyle MVVM üzerinde tartışılan bir çok yanı mevcut. Örneğin MVVM’de sıkça kullanılan ve bir EventAggregator (Fowler) uygulaması olan  Mediator-Mesenger konusunu incelemenizi öneririm. Önce View ve Önce ViewModel konularına da umarım ileriki yazılarımızda daha geniş girebiliriz, bu iki yöntemi nasıl uygulandığı Blendability’yi oldukça etkilemektedir. Tabi değinmediğimiz bir diğer konu da MVVM’in bize sağladığı faydalardan olan test edilebilirliğin uygumalarıdır. Bunları sonra yazmayı planladığım makalelerde bu konulara değinmeyi düşünüyorum.

Makale serimiz (şimdilik) burada sona eriyor. Birlikte MVVM projeleri üzerinde çalışırken görüş alışverişi yaptığımız Niyazi Toytok, Ali Bülbül ile Ömer Kul’a ve makaleleri gözden geçiren Doğan Akhan’a  teşekkür ederim. Okuduğunuz için de sizlere teşekkür ederim. MVVM ile ilgili her türlü sorunuzu mail ile bana iletebilirsiniz: berkesokhan et cimeyl dat kom   \m/ (*_*) \m/

 

MVVM konusunda tonla İngilizce makale olmasına rağmen Türkçe içeriğin (her zaman ki gibi) eksik olması ve Türkiye'de bilinirliğini arttırmak amacıyla MVVM hakkında bir makale yazmayı düşünüyordum. .NET Framework teknolojileriyle ilgili yazılım geliştiricilere yönelik çıkması planlanlanan ancak çeşitli sebeplerden dolayı iptal edilen bir dergi için aylar önce yazdığım orijinal makalemi bu amaçla düzenleyerek - ve bir blog postu için uzun olduğu için bölerek - sizlerle paylaşıyorum.

1. WPF ile Model View ViewModel: Giriş
2. WPF ile MVVM: Model
3. WPF ile MVVM: View
4. WPF ile MVVM: ViewModel
5. WPF ile MVVM: Parçaları Birleştirmek
Seriye ait kaynak kodlar: MvvmWithWpfSample.rar (245,34 KB)

ViewModel (VM), diğer bir değişle “model of a view”, View’ın bir çeşit modelidir. Üzerinde View’ın durumunu ve davranışlarını tutar.  View’ın sunabilmesi için bazen ham, yani direk olarak Model’in özelliklerini, bazen de (altında genellikle model özellikleri olacak şekilde sarmalayarak) kendi üzerinde özellikler tanımlar. Model’i, View’ın sunabileceği hale getirdiği için VM’i “aslında koca bir dönüştürücüdür” şeklinde tanımlayanlar olmuştur (Josh Smith).

ViewModel’in önemli bir sorumluluğu da Model’i direk refere ettiği için Model servislerini çağırmasıdır. View’lar ViewModel üzerinde tanımlanan özelliklere “bind” ederler. Bu özelliklerden bir kısmı da aslında View’ın Command’larını çalıştıran delegelerdir. Delegeler çağrıldığında, örneğin müşteri arama komutu gerçekleştiğinde, VM bu isteği gerekli parametreleri sağlayarak Model’e iletir ve Model’in cevabını alarak View tarafından kullanılabilecek hale getirir.

MVVM tasarım kalıbı, aynı Fowler’ın PM’de bahsettiği gibi GUI (yani View) veya ViewModel tarafında bir özelliğin değeri değiştirildiğinde diğer tarafın da bundan haberdar olmasını gerektirir. View tarafında bu işlem Binding mekanizmaları ve GUI bileşenleri ile kolayca halledilir. Örneğin View’daki bir metin kutusuna yazılan bir metin Binding deklerasyonu ile tanımlandığı ölçüde otomatik olarak VM’de bağlandığı özelliği günceller. Ancak VM, yani kod tarafından yapılan bir değişiklik View tarafından otomatik olarak algılanamaz. Örneğin müşteri arama komutu sonucu Model’imizden dönen bir dizi Customer nesnesinin CustomersFound koleksiyonunu doldurduğunu düşünelim, ne yazık ki böyle bir durumda binding tanımlarımızın eksiksiz olmasına rağmen View, yani GUI’miz otomatik olarak kendini güncelleyerek bulunan müşterileri göstermez. View’ımıza ilgili VM özelliğinin değiştiğini haber verecek bir mekanizma gereklidir. System.ComponentModel isim uzayında bulunan INotifyPropertyChanged arayüzü bu işlevi sağlar. Bu arayüz sadece bir PropertyChanged event’i tanımlar.  View içindeki WPF mekanizmaları, DataContext özelliğine referansı atanmış nesne INotifyPropertyChanged arayüzünü uyguluyorsa PropertyChanged event’ini işleyecek şekilde kendini kaydeder. Böylelikle bir VM özelliği değişirse View, kaydolduğu VM PropertyChanged eventi sayesinde bundan haberdar olur ve üzerinde gerekli güncellemeyi gerçekleştirir. INotifyPropertyChanged mekaniklerinin View tarafındaki kısmı WPF tarafından otomatik gerçekleştirilmesine rağmen, özellik değişince VM tarafında bu event’i tetiklemek yine MVVM geliştiricisine kalır. MVVM altyapılarında INotifyPropertyChanged implementasyonu genellikle bütün VM’lerin türediği kök bir sınıfta halledilir, ancak tetikleme işlemi bir şekilde VM özelliğinin setter’ına sızabilir.

Örnek senaryomuz için SearchWindowViewModel adlı bir sınıf oluşturup, SearchWindowView’ımıza bind edilmek üzere özelliklerimizi Diyagram 3’de görüldüğü üzere oluşturuyoruz.

ViewModel Sınıflarımız

Dikkat edilirse SearchWindowView sınıfının içi inşa edici metodu dışında boştur, yani View’ın code behind’ını boş tutma çabalarımız sonuç vermiştir. SearchWindowViewModel üzerinde tanımlanmış özellikleri inceleyelim. CustomerNameSearched, GUI’mizdeki arama metin kutusunun Text özelliğine bağlanmıştır. CustomersFound, GUI’deki arama sonucu gözükecek listenin öğelerine bağlanmıştır. IsCustomerSearchResultsVisible arama sonucu gözükecek listenin Visibility’sine bağlanmıştır. SearchCommand ise “Listele” butonunun Command’ı olarak bağlanmıştır.

Özelikle değinilmesi gereken iki noktadan biri CustomersFound koleksiyonunun bir ObservableCollection olmasıdır. Bunun sebebi senaryomuzda kullanılmasa bile CustomersFound koleksiyonuna herhangi bir öğe eklenip çıkarıldığında GUI’mizin kendini güncellemesini istememizdir.  Tahmin edeceğiniz üzere ObservableCollection’ın normal bir koleksiyondan tek farkı, INotifyPropertyChanged arayüzünü uygulamış olmasıdır.

Değineceğimiz ikinci nokta ise SearchCommand’dır. Bu özellik ICommand, tipindedir ve içerisinde OnSearchCommand’ı sarmalayan bir DelegateCommand nesnesi döndürür. DelegateCommand, kullanıcı tanımlı ICommand oluşturmayı kolaylaştırmak için geliştirilen benzeri sınıflardan biridir ve Microsoft tarafından geliştirilen uygulama geliştirme altyapısı Prism’in bileşenidir. Aşağıda bulunan "Command Sorunsalı Üzerine” adlı başlıkta Command’larla ilgili daha fazla bilgiye yer vereceğiz.

Kullanıcı uygulamayı çalıştırıp, arama kutusuna giriş yaptıktan sonra, “Listele” butonuna tıkladığında, VM üzerindeki OnSearchCommand çalışacak ve Model’i sorgulayıp gerekli bilgileri aldıktan sonra, üzerinde bulunan CustomersFound koleksiyonunu dolduracak ve IsCustomerSearchResultsVisible özelliğini true değerine çekecektir. VM üzerinde güncellenen az önce saydığımız özellikler setter kısımlarında ViewModelBase de tanımlı PropertyChanged event’ini tetikledikleri için de, bu event’i dinleyen View kendini güncelleyerek sonuçları kullanıcıya gösterecektir.

Command Sorunsalı Üzerine

WPF bize MVVM için birçok olanak tanımasına rağmen View’daki bileşenlerin event’lerini VM’deki Command‘lara Binding yaparak çözmek, aslında bazı zorlukları da beraberinde getirir. Command’ların tasarım nedeni, birden fazla kaynaktan (ICommandSource), gelebilecek aynı işlevin tek bir nesne ile simgelemektir. Örneğin bir metin kutusundan fare ile seçerek “Kopyala” komutunun verilmesi ile klavye ile CTRL+C yapılması durumunda ApplicationCommands.Copy komutu gönderilir. Kendi komutunuzu oluşturmak istediğinizde ICommand arayüzünü implemente eden bir sınıf yazmanız gerekir. Ayrıca komutunuzun hangi metodu çalıştıracağıyle ilgili CommandBinding’ini de ya XAML içine, ya da code behind’a el ile kodlayarak koymalısınız. Sıkıntılar burada bitmiyor, her View bileşeni bir ICommandSource olmadığından Command’ları tetikleyeceğiniz bileşenler de sınırlıdır. Yine aynı şekilde Command’ların tetikleneceği eventler’de sınırlıdır. Bütün bunları aşmak amacıyla MVVM altyapısı geliştiricileri, DelegateCommand (Prism), RelayCommand (JoshSmith), SimpleCommand (Marlon Grechs) gibi ICommand implementasyonları ve bunları XAML’da ilgili element’de deklare etmeyi sağlayan AttachedBehaviour veya DependencyProperty’ler oluşturmuşlardır.

WPF ile MVVM: View (MVVM-3)

November 26, 2010

MVVM konusunda tonla İngilizce makale olmasına rağmen Türkçe içeriğin (her zaman ki gibi) eksik olması ve Türkiye'de bilinirliğini arttırmak amacıyla MVVM hakkında bir makale yazmayı düşünüyordum. .NET Framework teknolojileriyle ilgili yazılım geliştiricilere yönelik çıkması planlanlanan ancak çeşitli sebeplerden dolayı iptal edilen bir dergi için aylar önce yazdığım orijinal makalemi bu amaçla düzenleyerek - ve bir blog postu için uzun olduğu için bölerek - sizlerle paylaşıyorum.

1. WPF ile Model View ViewModel: Giriş
2. WPF ile MVVM: Model
3. WPF ile MVVM: View
4. WPF ile MVVM: ViewModel
5. WPF ile MVVM: Parçaları Birleştirmek
Seriye ait kaynak kodlar: MvvmWithWpfSample.rar (245,34 KB)

View’larımız, görsel öğelerin tanımlandığı, (bir sekme kontrolünün sekmeler arasında geçişi gibi GUI bileşenlerinin doğal bir parçası olan veya bir animasyon gibi yine GUI amaçlı tasarlanmış dinamizm dışında) içinde mümkün olduğunca az interaktivite kodu içeren kullanıcı arabirimi tanımlarıdır. XAML ile pencerelerimizi, kullanıcı kontrollerimizi ve kullanıcının ulaşabileceği tüm GUI’yi tasarlarız.

MVVM’in önemli bir özelliği olarak, UX tasarımcısı ile yazılım geliştiricinin paralel çalışmasına olanak sağladığını söylemiştik. Bunu sağlamak için GUI tasarlanırken XAML’ın code behind’ına kod yazılmaması gerektiği tekrar hatırlatalım. Tasarımcı butonları ve listeyi yerleştirir ancak Button_Click gibi bir olay işleme metod tanımı yapmaz. İleride göreceğimiz üzere bunu geliştirici de yapmaz. Çünkü Button.Click gibi eventler’ı (olay?) işlemek yine View’ın bir parçası olarak gördüğümüz code behind’ı kullanmayı gerektirir. Ancak birinci motivasyonumuz olan GUI’nin kendisi ile etkileşimini ayırmak presibiyle çeliştiğinden dolayı MVVM’de mümkün olduğunca klasik olay işleme metodlarını kullanmayız.

Peki bir butona tıklandığında yapılması gerekenleri nasıl açıklayacağız? Elimiz kolumuz bağlı gibi gözükmesine rağmen yine WPF’in içinde gelen Command altyapısı bu durumda bize yardımcı olur. View tasarımımızı yaparken, veya View ve ViewModel geliştirilmesi bitirildiğinde, butonumuzun üzerinde bulunan Command özelliklerine, tıklandığında çalışacak kodlarımızı içeren ViewModel metodumuzu “Bind” ederiz diğer bir değişle bağlarız. WPF Binding mekanizmalarını yoğun olarak kullanacağımızdan bahsetmiştik, öyle ki GUI’mizde gözükecek ve girilecek verileri bağlamanın yanında GUI bileşenlerinin interaktivitesinde çalışacak kodları da aslında bir çeşit veri bağlama ile tanımlarız.

View’lar konusundaki bilinmesi gereken bir konu da blendability’dir. Microsoft Expression Blend, XAML ile WYSIWYG tadında ve kod düzenleme de yapabildiğiniz GUI tasarlamak için kullanılan bir tasarımcı aracıdır. Blendability ise bu uygulamanın XAML dosyalarını, MVVM uygulamamız çalışmadan, yani tasarım zamanında ne kadar başarılı sunduğunu gösteren bir ölçüdür.  İyi bir blendability’ye sahip bir projede tasarımcılar daha rahat çalışabilir.

Modelimizde bulunan müşterileri aramak için Ekran-1’de görünen basit GUI’yi kullanıyor olacağız.

Demo Kullancı Arayüzü

Senaryomuza göre kullanıcılarımızı isimlerine göre arayıp, bilgilerini listeleyebilmeliyiz. Bu aşamada üretilen SearchView.xaml dosyasına baktığımızda, herhangi bir bağlama veya olay yönetimi veya bir Command ile ilgili bir deklerasyon bulunmaz. Tasarımcı çalışırken, C# kodlarıyla ilgisiz – içinde JavaScript kodu olmayan bir HTML dosyası benzeri – xaml dosyaları hazırlar. Örnek  senaryomuz için SearchWindowView’ını oluşturuyoruz (Kod 1). View’ımız şimdilik bir veri bağlama (binding) içermiyor, ViewModel’imizi oluşturduktan sonra gerekli veri bağlamalarımızı tanımlıyor olacağız.

<Window x:Class="WpfApplication.Views.SearchWindowView"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Arama" Height="350" Width="525">
    <StackPanel Orientation="Vertical">
        <StackPanel Orientation="Horizontal">
            <TextBlock Text="Müşteri İsmi" Width="86" Height="24" Margin="12,10,0,10" Padding="0,5,0,0"></TextBlock>
            <TextBox Width="217"  Height="24" Margin="10,10,0,10"/>
            <Button Width="100"  Height="24" Margin="10,10,0,10">Listele</Button>
        </StackPanel>
        <StackPanel>
            <ListView>
                <ListView.View>
                    <GridView>
                        <GridViewColumn Header="Müşteri No" Width="Auto">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBlock VerticalAlignment="Center"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Adı" Width="Auto">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBlock VerticalAlignment="Center"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                        <GridViewColumn Header="Soyadı" Width="Auto">
                            <GridViewColumn.CellTemplate>
                                <DataTemplate>
                                    <TextBlock VerticalAlignment="Center"/>
                                </DataTemplate>
                            </GridViewColumn.CellTemplate>
                        </GridViewColumn>
                    </GridView>
                </ListView.View>
            </ListView>
        </StackPanel>
    </StackPanel>
</Window>
Kod 1: SearchWindowView

ViewModel tamamlandıktan sonra, veya ViewModel’imizin nasıl olacağı hakkında bir fikrimiz mevcutsa VM henüz bitirilmeden, binding yani veri bağlama ifadeleri View’a eklenir. View’da yer alan bağlama ifadelerinde, ViewModel’in özelliklerine atıfta bulunulur. View’lar, ViewModel’in üzerindeki özelliklere bağlanabilmek için ellerinde bir nesne örnek referansı barındırmak zorundadirlar. Bunun için ViewModel, View kök element’i üzerinde bulunan ve WPF’de bir çok bileşenin türediği FrameworkElement’ten miras alınan object tipindeki DataContext’e atanır. DataContext, View içindeki tüm element’ler için özelliklerine bağlanabilecekleri bir kök nesne sağlar.

View’larınız genellikle Window, Page veya UserControl’den türeyecektir, ancak bunlarla sınırlı değildir. ViewModel örneğinin referansını atayacağımız, DataContext’i olan herhangi bir FrameworkElement View tanımlamak için kullanılabilir.

View .xaml dosyalarınızı isimlendirirken genellikle sonuna “...View” eki konması geleneği mevcuttur. Kod-1’de listelediğimiz View’a arama yapacağı için ve bir pencere olduğu için “SearchWindowView” adını verdik. View’lar aslında birer XAML dosyası olduğu için WPF/Silverlight ile ilgili kurallar, View’lar için de aynen geçerlidir. Tek unutulmaması gereken mümkün olduğunca code behind kullanımından kaçınılması gerektiğidir.

WPF ile MVVM: Model (MVVM-2)

November 26, 2010

MVVM konusunda tonla İngilizce makale olmasına rağmen Türkçe içeriğin (her zaman ki gibi) eksik olması ve Türkiye'de bilinirliğini arttırmak amacıyla MVVM hakkında bir makale yazmayı düşünüyordum. .NET Framework teknolojileriyle ilgili yazılım geliştiricilere yönelik çıkması planlanlanan ancak çeşitli sebeplerden dolayı iptal edilen bir dergi için aylar önce yazdığım orijinal makalemi bu amaçla düzenleyerek - ve bir blog postu için uzun olduğu için bölerek - sizlerle paylaşıyorum.

1. WPF ile Model View ViewModel: Giriş
2. WPF ile MVVM: Model
3. WPF ile MVVM: View
4. WPF ile MVVM: ViewModel
5. WPF ile MVVM: Parçaları Birleştirmek
Seriye ait kaynak kodlar: MvvmWithWpfSample.rar (245,34 KB)

Model bileşenleri, diğer bir çok mimari tasarım kalıbında olduğu gibi, iş mantığı veya bunlara ait servislerin bulunduğu bileşenlerdir.

Monolitik bir uygulamada domain nesneleri, validasyon ve domain servisleri bu katmanda yer alır. Bu katmandan aşağı doğru veritabanı sorgu ve komutları gider.

Dağıtık bir uygulamada ise, genellikle bir uygulama sunucusuna yapılan web servis veya remoting gibi çağrıları yöneten servis sınıfları, validasyon sınıfları ve uygulama sunucusuna yapılan çağrıları ve cevapları taşıyan mesaj bileşenleri olan Veri İletim Nesneleri (Data Transfer Object – DTO’lar)  yer alır. Eğer klasik ASP.NET 2.0 Web Servisleri çağrılarak uygulama sunucusuyla iletişim kuruluyorsa, Visual Studio ile verilen referens sonucu otomatik üretilen web servis vekil (proxy) sınıflarının model sınıfı olarak kullanılması tavsiye edilmez. İleride bahsedeceğimiz ve WPF ile kurulan MVVM tasarım kalıbının önemli (ve belki de en rahatsız edici?) öğelerinden biri olan INotifyPropertyChanged arayüzünün modelde bulunan veri sınıfları tarafından uygulanması gerekebilir. Bu durumda, üzerinde kontrolümüz olmayan Visual Studio tarafından üretilmiş sınıfları kullanmak yerine, kendi istemci tarafı model sınıflarımızı oluşturmamız gerekecektir. Klasik ASP.NET web servisleri yerine, Windows Communication Foundation (WCF) altyapısıyla hazırlanan servisler kullanarak modelimizi oluşturursak istemci tarafında, uygulama sunucusunda oluşturulan mesaj kütüphanesini (DTO’ları, birer WCF Servis Kütüphanesi projesinde tanımlayarak) aynen kullanabiliriz. Bu yöntemin avantajı istemci tarafında model için DTO->model nesne eşleştirmesine sahip olmadan kullanmak olacaktır. Kabul edilebilir bir tasarım sorunu ise sunucu tarafındaki bu DTO’larda istemcinin ihtiyaç duyacağı INotifyPropertyChanged arayüzünün uygulanması, yani istemci ile ilintili kaygıların sunucuya sızmasına olanak verilmesidir.

Diagram 2’de makalemizde kullanmak için oluşturduğumuz örnek bir model mevcuttur.

Örnek Modelimiz

Görüldüğü gibi model sınıflarımız bildiğimiz POCO’lardan (Plain Old CLR Object) oluşmaktadır. Bu POCO’ları yukarıda tartıştığımız gibi, ister ASP.NET servis referansı sonucu üretilen DTO’lardan nesne eşleştirmesi ile (örneğin AutoMapper kullanarak), isterseniz WCF ile hem sunucu hem de istemcide ortak kullanarak ve DataContract betimlemeleriyle oluşturabilirsiniz. Model, basit ve anlaşılır olmak amacıyla, bilindik senaryo olan müşteri bilgisi senaryosunu tasvir edecek şekilde tasarlandı. Müşterinin kişisel bilgilerini, adresini, şehir ve telefon bilgilerini içeren (Diagram-1) modelin anemik olması gözünüze çarpmış olabilir. Bunun birinci sebebi, MVVM için modelin diğer M içeren kalıplardan pek farklı olmamasıdır, dolayısıyla üzerinde fazla durmayacağımız basit bir tasarım yeterlidir. İkinci sebep ise istemci-sunucu tarzı bir mimaride DTO kullanılacağını varsayarsak istemci tarafındaki model nesnelerinizin elle tutulur bir miktarda iş mantığı içermemesi gerekmesidir. Model üzerinde yapacağımız operasyonları View ve VM konularında anlatacağız.


MVVM konusunda tonla İngilizce makale olmasına rağmen Türkçe içeriğin (her zaman ki gibi) eksik olması ve Türkiye'de bilinirliğini arttırmak amacıyla MVVM hakkında bir makale yazmayı düşünüyordum. .NET Framework teknolojileriyle ilgili yazılım geliştiricilere yönelik çıkması planlanlanan ancak çeşitli sebeplerden dolayı iptal edilen bir dergi için aylar önce yazdığım orijinal makalemi bu amaçla düzenleyerek - ve bir blog postu için uzun olduğu için bölerek - sizlerle paylaşıyorum.

1. WPF ile Model View ViewModel: Giriş
2. WPF ile MVVM: Model
3. WPF ile MVVM: View
4. WPF ile MVVM: ViewModel
5. WPF ile MVVM: Parçaları Birleştirmek
Seriye ait kaynak kodlar: MvvmWithWpfSample.rar (245,34 KB)

Model View ViewModel (MVVM), son günlerde adı sıkça duyulan ve genellikle WPF ile birlikte kullanılan bir mimari tasarım kalıbıdır. Bu makale ile başlayarak WPF’den bahsedip, MVVM’in bileşenlerinin neler olduğuna ve nasıl oluşturulup kullanılacağına değinmeyi düşünüyorum. İlerleyen makalelerde örnek olmak amacıyla basit bir MVVM uygulaması da geliştireceğiz. Tasarım kalıbından bahsetmeden önce, platform olarak kullanacağımız WPF kütüphanesine kısaca değinelim.

WPF


Çoğunuzun bildiği gibi, Windows Presentation Framework (WPF) önümüzdeki dönemde klasik Windows uygulamaları için Microsoft'un tercih ettiği GUI (Graphical User Interface - Grafik Kullanıcı Arabirimi) teknolojisidir. WPF ile, Microsoft, eskiyen grafik arabirim teknolojisi GDI/GDI+'ı bırakıp DirectX üzerine kurulu bir yeni bir model oluşturdu. DirectX kullanımı sayesinde WPF ile yeni görsel efektler (animasyonlar, grafik dönüşümler) ve arka planda donanım hızlandırması kullanımı da mümkün hale geldi. Görsel ve donanımsal iyileştirmelerin yanı sıra, WPF ile birlikte yeni bir yazılım geliştirme modeli de geldi. Bu yeni modele göre, sunum ile ilgili yazılım bileşenleri XML tabanlı Extensible Application Markup Language (XAML) dili kullanarak görsel tasarımcılar (veya yeni tabiriyle UX – user experience, yani kullanıcı deneyimi tasarımcıları) tarafından geliştirilirken, geri kalan uygulama mantığının klasik yazılım geliştiriciler tarafından geliştirilmesi planlandı. Ancak bu çalışma modelini destekleyerek geliştiricileri yönlendiren bir tasarım kalıbı olmadan, görsel bileşenlerin uygulama kodları arasına sızması, en azından büyük projelerde büyük bir olasılıktır. Sebebi ise her XAML dosyasının, içindeki görsel bileşenlerin tanımlandığı eş sınıfını tutan bir .xaml.cs uzantılı “code behind” dosyasına sahip olmasıdır (Yazılım geliştirme ortamının Visual Studio olduğunu varsayıyorum). Bu code behind sınıfı ile GUI bileşenlerine ulaşıp, değişiklik yapması söz konusudur. MVVM uygulamalarımızda iş mantığını GUI mantığından mümkün olduğunca ayırmak amacıyla code behind’ı kullanmamaya çalışırız.

WPF özellikle barındırdığı güçlü Binding yani bağlama mekanizmaları sayesinde MVVM’e uygundur. Binding mekanizmaları, Fowler’ın MVVM’e çok benzeyen Presentation Model (PM)’i anlatırken bir dezavantaj olarak vurguladığı “prezentasyon model’i ile view’ı senkronize edecek kod yazılması gerektiği” zorluğunu oldukça azaltır.

WPF ve İşletim Sistemleri Bağımlılığı

WPF, Microsoft.NET Framework 3.0 ile yayımlanmıştır. Bundan önce sürümü çıkan Windows XP SP2 ve Windows 2003 işletim sistemlerinde WPF uygulamalarını çalıştırabilmek için .NET Framework 3.0 veya WPF içeren daha yeni bir .NET Framework kurulumu yapılmalıdır. Daha yeni Windows Vista, Windows 7 veya Windows Server 2008’de WPF uygulamalarını çalıştırmak için bir kuruluma ihtiyaç duyulmaz. Burada dikkat edilmesi gereken nokta, sonradan .NET Framework kurulumu yapılması gereken iletim sistemlerinde, WPF’in, Windows tarafından kullanılan (geliştiricinin bilmesi veya müdahale etmesi gerekmeyan) bir emülator yardımıyla çalıştırıldığıdır. Emülasyon yardımıyla çalıştırılan WPF uygulamaları hafıza ve işlemci gib sistem kaynaklarını daha çok kullanır ve göreceli olarak (aynı donanımda) daha yavaş çalışır. Emülasyon yardımıyla çalışan uygulamalar ayrıca Windows Vista veya Windows 7 gibi işletim sistemlerinde emülasyonsuz çalışan kopyalarına göre çok ufak görsel farklar içerebilir. Tavsiye edebileceğim şey WPF uygulamanızı, güncel işletim sisteminizde test ettikten sonra, halen yaygın olarak kullanılan Windows XP kullanan bir makinaya da götürüp orada bir incelemeniz olacaktır.


MVVM


MVVM, yani Model View ViewModel, GUI ile iş mantığının entegre edilmesi yani sunum amaçlı düşünülmüş bir mimari tasarım kalıbıdır. MVVM, diğer mimari tasarım kalıplarına  göre daha yeni tanındığı için birçok şekilde yorumlanmıştır ve dolayısıyla farklı uygulamalara sahiptir.

MVVM, 3 tür bileşenin bir araya gelmesiyle oluşur: Model bir windows istemci için web servislerin veya iş mantığı bileşenlerinin ve verinin olduğu bloktur, View  görsel (işitsel?) kullanıcı deneyimi bileşenlerinin yer aldığı bloktur, daha çok (ve bu makalede de) WPF – XAML  bileşenleri kullanılarak uygulanır. ViewModel (VM), Model’in, View için gerekli biçime dönüştüğü, View’ın durumunun tutulduğu ve kullanıcı interaktivitesinin yönetildiği bileşenlerin bulunduğu bloktur.

Mimari Bloklar

MVVM’in bu kadar kısa sürede gündeme yayılmasını sağlayan ve Model View Controller (MVC), Model View Presenter (MVP) gibi diğer mimari kalıplardan sıyrılmasını sağlayan bileşen ve bence üçlemenin en önemli bileşeni ViewModel’dir. Model’in View’a yerleştirilmesi sırasında çeşitli şekillerde biçimlendirilmesini veya Model’de yeri olmayan sadece View ile ilgili bilgilerin (örneğin bir listenin görülebilir mi olduğunun) tutulmasını sağlayan, ayrıca MVC’deki Controller’ın görevlerini de üstlenen ViewModel bileşenleridir. Farklı MVC uygulamaları, MVC tanımında olmamasına rağmen ihtiyaç nedeniyle Controller’a ek olarak kendilerine has ViewModel implementasyonları kullanır.

Peki MVVM kullanmanın faydaları nelerdir, niçin bir WPF uygulamasında MVVM mimarisi uygulamalıyız?

MVVM, tasarımsal bileşenler ile kullanıcıların bunlar ile etkileşimi halinde çalışacak kodların iyi bir ayrımını sağlar. En basit izahı ile bir butonun nerede duracağı, boyutlarının ne olacağı gibi deklaratif tasarım özellikleri ile butona tıklandığında ne yapacağı gibi prosedürel tanımların farklı sınıflarda olmasını sağlar ve bu sayede test edilebilirliği arttırır. Butonun ne yapacağı ile ilgili kod bloğunun bulunduğu sınıfta (ki bir ViewModel sınıfından bahsediyoruz), GUI referensı olmadığı için, gerçek bir GUI olmadan dolayısıyla GUI testi gibi karmaşık konulara girmeden, tıklama olayını test edebilirsiniz. MVVM’in günümüz uygulamaları WPF ve Silverlight için tasarlandığı için, bu platformlarda geliştirdiğiniz uygulamalarda, Binding gibi platform mekanizmaları sayesinde el ile daha az kod yazarsınız. MVVM, Geliştirici-UX Tasarımcısı ayrımını desteklediği için yazılım geliştirme süreci paralel olarak dolayısıyla daha hızlı ilerler.

MVVM’in dezavantajları nelerdir diye sorulduğunda akla gelen ilk cevap John Gossman’ın da belirttiği üzere, WPF Binding’lerin yoğun kullanımı nedeniyle fazla veri girişi-gösterimi bir arada olan uygulamalarda yoğun hafıza tüketimi göze çarpar. MVVM, VM’den View’a referens verilemediği için ve code behind da kullanılmadığı için, Windows Forms’dan gelen kodlama alışkanlıklarına sahip geliştiriciler için ilk başta kısıtlayıcı ve zorlayıcı gelebilir, ancak ilerledikçe geliştiricilerin düşünce biçimi MVVM’e uyum sağlayacaktır.

MVVM Tasarım Kalıbı Tarihi Kökeni


İlk olarak Microsoft çalışanı John Gossman’ın bir blog postuyla tanınan MVVM, aslında kökleri Smalltalk’a dayanan eski bir kalıptır.  Bazıları, Martin Fowler’ın sunum kalıpları içinde MVP’yi ikiye ayırıp, bunlardan birini de Presentation Model (PM) olarak adlandırdığı içeriği MVVM’e çok benzer çalışmasını refere ederek,  MVVM’in aslında ismi değiştirilmiş PM tasarım kalıbı olduğunu iddia etse de, John Gossman, WPF Disciples adlı e-posta grubunda, MVVM teriminin Microsoft içinde eskiden Smalltalk ile çalışmış geliştiriciler tarafından kullanıldığını ancak kendisinin bunu sadece dışarıya açtığını belirtmiştir. Fowler ile yakın zamanlarda ve birbirlerinden habersiz olarak bu çalışmaları yaptığını da eklemiştir. Zaten Fowler, PM makalesinde aslında bu kalıbın Smalltalk’ta kullanılan Application Model’in aynısı olduğunu söyleyerek yine Smalltalk’a gönderme yapmıştır.

Birlikte Geliştir!

June 15, 2010

Türkiye'nin Açık Kaynak Topluluğu Birliktegeliştir Yeni Versiyonu İle Yayında

Açık kaynak kodlu proje geliştirme yaklaşımının giderek yaygınlaştığı günümüz yazılım dünyasında Microsoft platform ve araçları kullanılarak birçok açık kaynak kodlu uygulama geliştirilmekte ve Microsoft’un kendisi de bu konuda çalışmalar yapmaktadır.

Açık kaynak kodlu bir içerik yönetim sistemi olan Umbraco üzerine kurulan Birliktegeliştir, Türkiye’de de Microsoft platformlarında açık kaynaklı projeler geliştirilmesi ve mevcut açık kaynak kodlu projelerin kullanımının yaygınlaştırılmasını amaçlamaktadır. Zaman içinde yaygınlaşan açık kaynak kod topluluğuna daha iyi içerik sağlamak amacıyla Birliktegeliştir yeni arayüzü ve yeni özellikleriyle yayında.

Sizlerin de kendi projelerinizi ve kendi içeriğinizi rahatlıkla paylaşabileceğiniz Birliktegeliştir’de ayrıca Türkiye'de geliştirilmiş açık kaynak kodlu projelere, bugüne kadar dünyada yapılmış açık kaynak kodlu uygulamaların kullanımı ile ilgili makale, video gibi Türkçe kaynaklara ulaşabilirsiniz.

Bunun yanısıra uygulama geliştiricilerin kodlama sırasında çoğunlukla kullandığı kod bloklarına Kod Parçaları kısmından ulaşabilirsiniz.

Birliktegeliştir topluluğuna www.birliktegelistir.com adresinden ulaşabilirsiniz.

 

E-Mail: birliktegelistir@birliktegelistir.com  

Twitter: www.twitter.com/bgelistir


ALT.NET ilk defa Davi Laribee tarafından ortaya atılmış bir kelime. Microsoft ekosisteminde baskın durumda bulunan araçlardan ve yazılım geliştirme yaklaşımlardan farklı seçimler yapabilmeyi ifade etmek için Alternative'in ALT'ı ve buna karşın Microsoft'un baskın teknolojisi .NET'i birleştiren ilginç bir terim.

ALT.NET, üzerinde hala anlaşılmış kesin bir tanımı olmayan, ancak Microsoft platformları üzerinde kaliteli yazılım geliştirmek hedefi etrafında toplanan bir hareket. ALT.NET'çi olduğunu söylen herkesin kendine göre bir algısı ALT.NET algısı mevcut.

Benim ALT.NET algım ise şu şekilde: Sadece Microsoft'tan geldiği için bir teknolojiyi kullanmak veya Microsoft'ta bir karşılığı olmadığı için bir aracı kullanmamak yerine, neye ihtiyacınız varsa onu kullanmak. Araçlar ve teknolojinin pratik karşılıkları bir logging kütüphanesi de olabilir, agile yöntemleri destekleyen unit testler ve test driven development metodolojileri de olabilir. Kısaca ALT.NET'in bendeki karşılığı, gerekirse alternatifleri kullanarak, Microsoft platformunda iyi yazılım yapmaya çalışmak.



Dünyanın diğer yerlerinde olduğu gibi ALT.NET'in Türkiye'deki karşılığı da, bir mailing list ve düzenli yapılmaya çalışılan buluşmalar ve kişilerin blog postları (v= bunun gibi :)) şeklinde biçimleniyor.

İlkine katılamadığım ALT.NET toplantıları bundan yaklaşık 1,5 yıl önce başlamıştı. Katıldığım ilk buluşmanın, sabah oturumunda insanlar (Gürkan Yeniçeri, Gökhan Altınören, Doğa Öztüzün...) ALT.NET Türkiye'nin nasıl bir hedefi olması gerektiğini ve yazılım geliştirme süreçlerini tartışmıştı. Öğleden sonraki oturumda Tuna Toksöz ve Doğa Öztüzün C#, ASP.NET MVC ve NHibernate üzerinde kendi geliştirdikleri açık kaynak kodlu blog uygulaması BlogSharp'ı sundular. Tuncer Karaarslan ise NHibernate ile küresel navigasyon için spatial hesaplarının nasıl yapıldığından bahsetmişti.

Uzun süredir ara verdiğimiz ALT.NET buluşmalarından üçüncüsünü geçen hafta (2010-03-21) yapabildik. Bu buluşma öncekine göre daha dolu ve eğiticiydi. Daha önceki buluşmalara katılan arkadaşlar olduğu kadar, ALT.NET ile ilgilenen yeni yüzler de gördük. Sabah oturumunda Serdar Büyüktemiz Tuncer Karaarslan bu sefer Oracle ve spatial'den bahsetti. Serdar Büyüktemiz Search Engine Optimization konusunda oldukça bilgilendirici bir sunum yaptı. Öğleden sonra sahneyi Tuna Toksöz aldı ve Castle Windsor ile ilgili sunusunu paylaştı. Daha sonra ben de istek üzerine WPF MVVM ile ilgili kısa bir sunum yaptım.

Sunum yaparak bilgilerini paylaşan herkeze ve izleyicilere teşekkür ediyorum. Bilge Adam'ın desteğini alıp, bize yer ayarlayarak buluşmaların gerçekleşmesinde büyük emeğe sahip Murat Haksal'a da ayrıca teşekkür etmek isterim.

ALT.NET buluşmalarında sunuların kaydedilmiş tüm videolarını vimeo daki ALT.NET Türkiye grubuna yüklüyor olacağız. Burada bahsedilen ancak linki verilmeyen videoları vimeo'dan kontrol edebilirsiniz.

Sunum Videoları: ALT.NET Türkiye
ALT.NET Türkiye e-posta listesi: http://groups.google.com/group/altdotnetturkiye

We recently started to build a desktop application with WPF and MVVM.

When we had the need for a validation framework for our view inputs, I started to look on internet to find "de facto" approach for MVVM and WPF in general. There are lots of look-alike methods for validation.

For validation I commonly saw three approaches:

  • Validation Rules on views
  • Hand coded validation on ViewModel setters
  • Using some validation framework attributes (mostly System.ComponentModel.DataAnnotations) on binded Model properties or ViewModel properties.

For validation error user notification, people complain about how WPF lacks old Windows Forms built in Error Provider support and invent their custom ones with IDataErrorInfo interface.

The problems with the implementations I saw so far was they were like toy examples or have overly complex implementations. One implementation outstands for me from the rest.

In Mariano Omar Rodriguez's validation approach, ViewModel decorates its properties with Data Annotations for validation, and to check these attributes are really valid, ViewModel uses some reflection and Linq Expressions. To show errors ViewModel also implements IDataErrorInfo interface. While Mariano's approach seemed a little complex, if I could carry complexity (IDataErrorInfo implementation and reflection methods/properties) to a ViewModelBase class, adding new properties and validations would become fairly easy.

I modified Mariano's code with generics to move all those overhead to a base class. Two things I couldn't carry without friction were IDataErrorInfo's members this[string] indexer and Error property, because these properties send "this" instances to reflective methods for gathering IsValid infos from Data Annotation attributes. I was stuck there for a good solution. My collegue Niyazi came with a solution which suggests we should declare a T type property in ViewModelBase, and use T property instead of "this" in ViewModelBase and actual ViewModels which inherit from ViewModelBase should assign their selves to this generic typed property in their constructors. We were not totally ok with this yet another overhead for the ViewModel. But it's less crappy or less code from other solutions out there. So we settled for this solution.

You can grab the solution attached below. Please feel free to comment on this solution's possible drawbacks.

Samples.Validation.BerkesVariant.rar (83.76 KB)

Başlık herşeyi anlatıyor. Ama söz edilmesi gereken bir kaç değişiklik mevcut tabi ve söz de edilmiş:

Scott Guthrie: Visual Studio 2008 and .NET Framework 3.5 Service Pack 1 Beta
Scott Hanselman: VS2008 and .Net 3.5 SP1 Beta - Should You Fear This Release?
Somasegar's WebLog (MSDN Blogger): Visual Studio 2008 and .NET FX 3.5 SP1 Beta available now

Bir şey eklemek istemiyorum, çünkü eminim MS evanjelistleri onlarca defa aynı şeyi yazmışlardır. ;)

Ekleme:
    (tabii ki) InfoQ: New version of .NET Disguised as a "Service Pack"

From the author of The Reciprocality Project white papers:

"Reciprocality is a private project to better understand the nature of the stresses and challenges facing the
software industry at the moment, particularly in respect of deep cultural issues in the model of the nature of
work. The intention is to be able to assist organisations to create conditions where they can maximise their
ability to attract, retain and get the best from able staff, while ensuring that younger staff are provided with
the conceptual and technical mentoring necessary to develop into aware and effective creative engineers.

The project is evaluating 10 years teaching experience in a very broad social and cultural context, and
appears to be generating interesting results. It would seem that the way that software engineering is
perceived in society at large can tell us much about difficulties society will face as the economy becomes
more clearly dominated by Information Age issues."

- Alan Geoffrey Carter

I downloaded the whole project site in PDF and checked out some of the articles. Though it may be dated old, I think it contains some valuable information.