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)
 
Categories: .NET | C# | In English | MVVM | Teknik | WPF

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"


 
Categories: .NET | Araçlar | ASP.NET | C# | IDE | Teknik | Visual Studio

February 15, 2007
@ 06:25 PM

Belki geç kalmış bir bilgi ama yakın zamanda başıma geldiği için dikkat çekmek istedim,

Diyelim ki içinde veriler bulunan bir tabloyu çoğaltmak için DataTable.Clone() + ImportRow() yapmak istiyorsunuz, böyle bir durumda bu DataTable örneğine ait DefaultView (yani varsayılan DataView) e atanmış bir filtre (DataView.RowFilter) tanımlanmışsa bu filtrenin klonlanarak oluşturulmuş yeni DataTable'da yer almayacağını unutmamalısınız...

Örneğin : DataTable dtOrijinal = new DataTable(); ... dtOrijinal.DefaultView.RowFilter = "Isim = 'Ahmet'"; Console.WriteLine("Orijinal Filtre: " + dtOrijinal.DefaultView.RowFilter); ... DataTable dtClone = dtOrijinal.Clone(); Console.WriteLine("Klonun Filtresi: " + dtClone.DefaultView.RowFilter); şeklindeki bir kod parçacığı...

Orijinal Filtre: Isim = 'Ahmet' Klonun Filtresi:
şeklinde bir çıktı oluşturur.

Kısaca belirtmek gerekirse klonlar veriyi içermediği gibi filtreleri de içermiyor!

Ek olarak filtrelenmiş bir DataTable'ın satırları içinde dolaşırken filtre dışında kalan satırlara da ulaşırsınız. Dolayısıyla filtre edilmiş bir DataTable'daki verileri bir klona aktarırken satırları değil de DefaultView satırlarını dolaşmalısınız.

Örneğin sadece filtre kuralına uyan satırları import etmek istenen bir durumda aşağıdaki kod parçası istenen sonucu üretmez: foreach (DataRow dr in dtOrijinal.Rows) { this.dtClone.ImportRow(dr); } ...ama aşağıdaki kod parçası ile sadece filtre kuralıana uyan satırlar alınabilir: foreach (DataRowView drv in this.dtOrijinal.DefaultView) { this.dtClone.ImportRow(drv.Row); }


 
Categories: C#

May 3, 2006
@ 02:33 AM
.Net Framework 2.0 da C# ile object tipi bir nesneyi alıp bunu integer bir değere dönüştürürken acaba hangisi daha performanslıdır :

object deger = 1492; int.Parse(deger.ToString()); // Bu mudur? Convert.ToInt32(deger); // Yoksa bu mu? Lutz'un Reflector'ü ile mscorlib.dll'i açıp kodları incelediğimizde kesin yargıya ulaşamıyoruz. En iyisi gözlerimizle görmek diyerek konu hakkında minik bir uygulama yazdım.

Tester Uygulaması

public partial class Form1 : Form   
{   
object kurban = 1492;   
int sonuc;      

private void btnConvertTo_Click(object sender, 
    EventArgs e)   
{   
    for (int i = 0; i < 9000000; i++)   
    {   
        sonuc = Convert.ToInt32(kurban);   
    }   
    MessageBox.Show("Bitti!");   
}      

private void btnIntParse_Click(object sender, 
    EventArgs e)   
{   
    for (int i = 0; i < 9000000; i++)   
    {   
        sonuc = int.Parse(kurban.ToString());   
    }   
    MessageBox.Show("Bitti!");   
}  

}
Sonuçlara baktığımızda "ToString + int.Parse" butonuna tıkladığımızda 6sn sonra "Bitti!" mesajını görürken, "Convert.ToInt32" butonu 1sn içinde bize "Bitti!" mesajını gösterebiliyor.

Sizce hangisi daha performanslı?


 
Categories: C#