Merhabalar, daha önceki yazımda Dynamic Data Web Site'ını özelleştirebileceğimiz konusundan bahsetmiştim. Bu yazı özelleştirme konusuna giriş amacı taşımaktadır.

Dynamic Data Web Site'ın oluşturulmasıyla birlikte gelen sayfa şablonları üzerinden yazıma devam ediyorum.

Bazı veritabanlarında tablo isimleri kolon isimleri vb alanlar firmanın kullandığı standartlar kapsamında belirleniyor. Bir tablo adlandırması çok farklı prefixler alabilir, kısaltmalardan faydalanarak kullanılıyor olabilir yada okunuşu çok anlamsız bir şekilde olabilir. Bu temelde yazılımsal olarak bir sııntı oluşturmuyor ancak bu isimlendirme standartlarından kullanıcıların anlamasını beklemek çok yanlış olacaktır. Dynamic Data Web Site'ın çözüm için üzerinde modifikasyon(lar) yapılacak tabloya partial olan farklı bir class yazıyoruz ve class'a MetaDataType özniteliğini atıyoruz. Zor gibi görünen bu yapı kodlaması oldukca basittir.

Employee tablosunun List.aspx şablonunda görüntüsü:

Bu tablo modifikasyonlar yapmaya başlayalım. Tanımalayacağımız class partial olduğundan LINQ to SQL Class'ında generate edilmiş tablo adı ile aynı isimi taşıması gerekiyor. Tablonun atandığı class adını LINQ to SQL Class'ından tespit edilebilir.

Employee tablosu için yazılmış örnek MetaData sınıfı:

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

[MetadataType(typeof(EmployeeMetaData))]
public partial class Employee
{

}

public class EmployeeMetaData
{
    /*  Tanımlamalar burada yapılacak. */
}

 

Üzerinde değişiklik yapılmak istenen kolon için MetaData sınıfı içinde propery tanımlaması yapılmalı. Değişken adının aynı olması gerektiğini tekrar hatırlatıyım. Gelelim FirstName'in Name olarak gösterilmesi işleminin tanımlanmasına.

    [DisplayName("Name")]
    public string FirstName { get; set; }

Dikkat edilmesi gereken en önemli noktalardan birisi yapılan isim değişikliğinin FirstName alanının kullanıldığı tüm şablonlara yansıtılacağıdır.DisplayName özniteliği dışında bir çok özniteliği kullanarak modifikasyon işlemleri zenginleştirilebilir.

Görünmesini istemenmeyen herhangi bir alanı gizmelek için kullanılan öznitelik ataması

[ScaffoldColumn(false)]

Format ataması bildirimleri için DisplayFormat özniteliği kullanılabilir.

[DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}")]
public DateTime HireDate { get; set; }

Bazı durumlarda özelleştirilmiş FieldTemplate'ler kullanılması gerekiyor. Bu gibi durumlarda UIHint özniteliği kullanılabilir. Edit modu için herhangi bir tanımlama yapılmaz. [KontrolAdı]_Edit.ascx aranır yoksa varsayılan field ile çalışır. PhotoPath alanının gösterimi için Image kontrolünü kullanmayı düşünyorum. Varsayılan olarak Text şablonunu kullanmaması için aşağıdaki bildirimi yapıyorum.

[UIHint("ThumbImage")]
public string PhotoPath { get; set; }

ThumbImage şablonumun kaynak kodları şöyle

ThumbImage.ascx

<%@ Control Language="C#" CodeFile="ThumbImage.ascx.cs" Inherits="ThumbImageField" %>
<asp:Image runat="server" ID="imgThumb" ImageUrl="<%# FieldValueString %>" />

ThumbImage.ascx.cs

using System.Web.UI;
public partial class ThumbImageField : System.Web.DynamicData.FieldTemplateUserControl
{
    public override Control DataControl {
        get {
            return imgThumb;
        }
    }
}

Path'i alınan resimin thumbnail halini göstermem gerekiyor. Aksi halde görüntü kirliliği oluşabilir. Bu nedenle resimler için Generic Handler yazmamız sorunu çözecektir.



Edit şablonlarına örnek olması amacıyla farklı tipteki bir alana özel şablon geliştirelim. DateTime özel şablonunda DateTime Picker kullanımına örnek olarak aşağıdaki tanımlamayı yapıyorum. Projeye AjaxControlToolkit'i eklemeyi unutmayın.


[DisplayFormat(DataFormatString = "{0:dd.MM.yyyy}"),UIHint("CustomDateTime")]
public DateTime HireDate { get; set; }

CustomDateTime_Edit.ascx


<%@ Control Language="C#" CodeFile="CustomDateTime_Edit.ascx.cs" Inherits="CustomDateTime_EditField" %>

<%@ Register assembly="AjaxControlToolkit" namespace="AjaxControlToolkit" tagprefix="cc1" %>

<asp:TextBox ID="TextBox1" runat="server" CssClass="droplist" Text='<%# FieldValueEditString %>' Columns="20"></asp:TextBox>

<cc1:CalendarExtender ID="TextBox1_CalendarExtender" runat="server"
    TargetControlID="TextBox1">
</cc1:CalendarExtender>

<asp:RequiredFieldValidator runat="server" ID="RequiredFieldValidator1" CssClass="droplist" ControlToValidate="TextBox1" Display="Dynamic" Enabled="false" />
<asp:RegularExpressionValidator runat="server" ID="RegularExpressionValidator1" CssClass="droplist" ControlToValidate="TextBox1" Display="Dynamic" Enabled="false" />
<asp:DynamicValidator runat="server" ID="DynamicValidator1" CssClass="droplist" ControlToValidate="TextBox1" Display="Dynamic" />

CustomDateTime_Edit.ascx.cs


using System;
using System.Collections.Specialized;
using System.Web.UI;

public partial class CustomDateTime_EditField : System.Web.DynamicData.FieldTemplateUserControl
{
    protected void Page_Load(object sender, EventArgs e) {
        TextBox1.ToolTip = Column.Description;
       
        SetUpValidator(RequiredFieldValidator1);
        SetUpValidator(RegularExpressionValidator1);
        SetUpValidator(DynamicValidator1);
    }

    protected override void ExtractValues(IOrderedDictionary dictionary) {
        dictionary[Column.Name] = ConvertEditedValue(TextBox1.Text);
    }

    public override Control DataControl {
        get {
            return TextBox1;
        }
    }
}

Sonuç

İşlem DateTime varsayılan şablonu üzerinden yapılırsa tüm DateTime alanları bundan etkilenir. FieldTemplate'lerin zenginleştirmesi daha sonraki projelerde kullanılabileceğinden iyi bir yatırımdır.  Dynamic Data'nın Routing yapısı üzerine kurulu olmasından dolayı FileUpload vb. işlemleri yapılabilmesi için farklı yöntemler izlemek gerekiyor. Bu konuyu da farklı bir yazı konusu olarak düşünüyorum.

Gelelim kullanıcı ve sunucu taraflı doğrulama işlemlerine. FieldTemplate'ler üzerinde yapılabileceği gibi olay tabanlı doğrulama işlemlerinin yapılmasıda mümkün oluyor. Ekleme, güncelleme, silme gibi işlemleri MetaData ile çok kolay bir şekilde denetleyebiliyoruz ve gerek duyulan durumlarda hata fırlatma yöntemi ile Dynamic Data'nın durumu farketmesini sağlayabiliyoruz. Varsayılan alan şablonlarında veri tipi tanımlamasına uygun veri girdileri sağlamak adına standart doğrulama işlemleri mevcut. Fakat bazı durumlarda bazı alanlar için özel tanımlama yapılması gerekebilir.

Aralık bildirimi için kullanılan Range özniteliğine bir örnek:


[Range(0,30,ErrorMessage="This area should be a value between 0 to 30.")]
public System.Nullable<short> UnitsInStock { get; set; }



Sunucu tabanlı doğrulama işlemleri tanımlamak bazı durumlarda zorunludur. Product tablosundaki stok alanı ile siparişteki ürün sayısını tutan alanın birbiriyle tutarlı çalışması gerekiyorsa yani güncelleme olayında girilmiş stok sayısının verilen sipariş sayısından küçük olmasını engelleme veya tam tersi gibi işlemler için öznitelik ataması yapmak(özelleştirilmiş öznitelik de olabilir) mantıklı değildir. Bu yüzden güncelleme olayı için aşağıdaki kod yazılabilir. Yazacağımız method partial olacağından MetaData sınıfına yazmamız mümkün olmuyor. Method doğrudan MetaDataType özniteliğini atadığımız sınıf içinde tanımlanmalı.


using System;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

[MetadataType(typeof(ProductMetaData))]
public partial class Product
{
    partial void OnUnitsInStockChanging(short? value)
    {
        if (value.HasValue)
        {
            if (value < this._UnitsOnOrder)
            {
                throw new ValidationException("Customized test error message.");
            }
        }
    }
}

public class ProductMetaData
{
    [Range(0,30,ErrorMessage="This area should be a value between 0 to 30.")]
    public System.Nullable<short> UnitsInStock { get; set; }
}

Bu makaleyi de burada bitirelim. Daha derinlere ineceğiz ancak ilk etapda Dynamic Data'yı genel özellikleri ile ele alacağım. Bir sonraki yazıda görüşmek üzere.