Bilindiği üzere ASP.NET Dynamic Data ile birlikte kullanıcı etkileşimini sağlayacak sayfalar dynamic bir şekilde sunuluyor. Bu arayüz üzerinde yapılacak bazı güncellemelerle kullanım kolaylığı sağlaman üzere yola çıkıyoruz tabi birazda görsel de oynayalım. Yazının bir çok kısımında anlatım dili geliştirme sırasında .net le yaptığım dialogları yansıtmaktadır. Ayrıca projenin tamamını(resim, js vb.) yazamadığım için makalenin en altında zip dosyasını bulmanızı ümit ediyorum.
Çok fazla tablodan oluşan yapılarda meydana gelen tablo listeleme ekranından dolayı rahatsızlık yaşanabiliyor. Bunun için varsayılan şablonların default sayfasındaki tablo listesini masterpage de uygun bir yere alıp, tablo listeleme mantığında birazcık değişiklik yapalım.

Senaryoya göre çok fazla tablo var ve hangisinin nerede olduğunu bulmak kullanıcılar açısından problem olmaya başladı. Bu sebeple bir şekilde tablo listesinin kullanımını kolaylaştırmalıyız. Tablo listesini kendi içinde gruplayarak bu işi pratik bir şekilde çözebileceğimizi düşünüyorum. Menü masterpage de uygun bir yere alınıp her sayfadan erişimi kolaylaştırılmalı ve gruplama işlemini tanımlamak üzere öznitelik sınıfı yazılmalıdır. Tabi ki son olarak da menunün datasource kısımını biraz değiştirmemiz gerekecek.
Menüyü oluşturan gridview kontrolünü ve veribağlama işlemi için kullanılan kodları masterpage tarafına aktaralım. MasterPage tarafında 1x2 tablosu oluşturup menüyü sol hücreye aldıktan sonra default.aspx’e hoşgeldiniz tarzı bir metin yerleştirelim(Daha sorna hoşgeldiniz yazısı yerine istatistik, özet bilgi ekranı vb. yapılabilir).

Aşağıdaki sınıfı gruplama işlemlerini MetaData üzerinden bildirebilmek için yazalım.
using System;
/// <summary>
/// Ömer Faruk ZORLU
/// </summary>
public class MenuInfoAttribute : Attribute
{
/// <summary>
/// Gruplandırma adını taşır. Üyelik Grubu, Sipariş
/// Menüsü gibi
/// </summary>
public string Name { get; set; }
/// <summary>
// Menüler sıralanırken göz önünde
// bulundurulacak sıralama ölçütüdür.
// Değerin tersi yönünde sıralama yapılır.
/// </summary>
public int Priority { get; set; }
/// <summary>
/// Files/Icon/{IconDegiskeni}.png yolu üzerinden
/// resimlerin yüklenmesi sağlanır. Değer ataması yaparken
/// dosyanın uzantı noktasından önceki kısımı yazılır.
/// </summary>
/// <example>myIcon.png için myIcon değeri atanmalıdır.</example>
public string Icon { get; set; }
public MenuInfoAttribute(string name, int priority)
: this(name, priority, string.Empty)
{ }
public MenuInfoAttribute(string name, int priority, string icon)
{
this.Name = name;
this.Priority = priority;
this.Icon = icon;
}
/// <summary>
/// Sıralama işleminde kullanılmak üzere yazılmıştır. Linq'in
/// orderby işlevini özelleştirmek amacıyla kullanılmıştır.
/// </summary>
/// <param name="obj"></param>
/// <returns></returns>
public override bool Equals(object obj)
{
if (obj == null) return false;
return this.Name.Equals(((MenuInfoAttribute)obj).Name);
}
}
Sınıfı yazdıktan sonra MenuInfo sınıfına MetaTable sınıfları üzerinden kolay erişebilmek adına aşağıki extension sınıfını yazalım.
using System.Linq;
using System.Web.DynamicData;
public static class MetaTableExtensions
{
/// <summary>
/// Tablolara atanmış MenuInfo özniteliğini dönderir. Eğer MenuInfo ataması
/// yapılmamışsaOthers isimli bir grub içinde oldukları kabul edilir.
/// </summary>
/// <param name="table"></param>
/// <returns></returns>
public static MenuInfoAttribute GetMenuInfo(this MetaTable table)
{
return table.Attributes.OfType<MenuInfoAttribute>().DefaultIfEmpty(new MenuInfoAttribute("Others", -10)).FirstOrDefault();
}
}
Bu aşamadan sonra masterpage içine aldığımız menünün yapısını değiştirmemiz gerekiyor. Halihazırda kullanılan GridView kontrolünün yerine ListView kontrolünü iç içe iki adet olacak şekilde tasarlıyorum. Dıştaki ListView kontrolü kategori gruplamalarını içte Repeater ise o kategorideki tabloları listelemekle görevli olacak. Tanımlamaya ait kod bloğu:
<asp:ListView ID="lvMenu" runat="server">
<LayoutTemplate>
<table style="width: 150px;">
<tbody>
<tr>
<td>
<table id="itemPlaceHolder" runat="server" />
</td>
</tr>
</tbody>
</table>
</LayoutTemplate>
<ItemTemplate>
<table rules="all" cellspacing="0" cellpadding="6" border="1" style="border-collapse: collapse;"
id="ContentPlaceHolder1_Menu1" class="DDGridView">
<tbody>
<tr class="th">
<%# SetRowsVisible(ToSEFString(Eval("GName").ToString())) %>
<th scope="col" style="height: 18px;" tblname='<%# ToSEFString(Eval("GName").ToString()) %>'>
<table>
<tr>
<td style="width: 18px;">
<%# GetIconOutput(Eval("Icon"))%>
</td>
<td>
<%# Eval("GName") %>
</td>
</tr>
</table>
</th>
</tr>
<asp:Repeater ID="rp1" runat="server" DataSource='<%# Eval("Tables") %>'>
<ItemTemplate>
<tr class="td jqMenutd" <%# GetDisplayCase() %>>
<td>
<asp:DynamicHyperLink ID="HyperLink1" runat="server"><%# Eval("DisplayName") %></asp:DynamicHyperLink>
</td>
</tr>
</ItemTemplate>
</asp:Repeater>
</tbody>
</table>
<br />
</ItemTemplate>
</asp:ListView>
MasterPage’e ait kodlar:
using System;
using System.Linq;
using System.Text.RegularExpressions;
using System.Web;
using System.Web.DynamicData;
public partial class Site : System.Web.UI.MasterPage
{
protected bool isRowVisible = false;
protected void Page_Load(object sender, System.EventArgs e)
{
var sonuc = from p in MetaModel.Default.VisibleTables
orderby p.GetMenuInfo().Priority descending
group p by p.GetMenuInfo() into groups
select new
{
GName = groups.Key.Name,
Icon = groups.Key.Icon,
Tables = groups
};
lvMenu.DataSource = sonuc;
lvMenu.DataBind();
}
protected string GetIconOutput(object objIcon)
{
if (objIcon == null)
return string.Empty;
return string.Format("<img src='{0}Files/Icons/{1}' />", GetAbsolutePath(), objIcon);
}
public string GetAbsolutePath()
{
return VirtualPathUtility.ToAbsolute("~/");
}
protected string SetRowsVisible(object obj)
{
if (obj == null || Convert.ToString(obj) == string.Empty)
isRowVisible = false;
HttpCookie httpCookie = Request.Cookies["ak_" + Convert.ToString(obj)];
if (httpCookie != null && httpCookie.Value == "out")
isRowVisible = false;
else
isRowVisible = true;
return string.Empty;
}
///
protected string GetDisplayCase()
{
return !isRowVisible ? "style='display:none'" : string.Empty;
}
/// <summary>
/// Türkçe karakterler bloklanıyor
/// </summary>
/// <param name="str"></param>
/// <returns></returns>
public string ToSEFString(string str)
{
return Regex.Replace(str, "ö|ç|ş|ğ|ü|ı|Ç|Ö|İ|Ş|Ü|Ğ", "_");
}
}
Bu aşamaya kadar gelmişseniz şuanki sayfa çıktısı aşağıdaki gibi olacaktır. Tablo başlığındaki “Others” yazısını görüyorsanız buraya kadar bir sorun yok demektir.

Gelelim menu tarafındaki kodlamanın son aşamasında –en sevdiğim kısımdır- MetaData bildirimlerini yapalım. Adres, kargo ve konum tablolarını “Bütünleşik Veriler” diye bir gruplandırmaya maruz bırakalım. Bunun için bu üç tablo üzerinde aşağıdaki MenuInfo tanımlamasının yapılması gerekiyor. Diğer tablolar içinde benzer tanımlamaları yapmış olalım.
Kargo tablosuna ait örnek MetaData sınıfı:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
[MetadataType(typeof(KargoMetadata))]
public partial class Kargo
{
[MenuInfoAttribute("Bütünleşik Veriler", 30, "text_ruler.png")]
public class KargoMetadata
{
}
}
Tanımlama işlemlerinden sonra menüde aşağıdakine benzer değişikliklerin görülmesi pek muhtemeldir.

Buraya kadar yaptığımız değişiklikler tablo karmaşasını büyük ölçüde engellemiş olacaktır. Ancak genel olarak biraz görsel değişiklik ve kullanım kolaylığı sağlamak hoş olur diye düşünüyorum. Bunun için css dosyasında biraz oynayarak aşağıdaki görünüme büründürdüm.

Açıkcası sol taraftaki menü ile ilgili biraz daha geliştirme yapmak istiyorum. Şuan baktığımda neden hepsi açık duruyor ki diyorum kendi kendime. Biraz javascript ile kasarsak grupları açılır kapanır hale getirebiliriz ve açma kapama olaylarınıda çereze aktarıp sayfa değişikliği olduğunda çerezden okuyup açılma/kapanma durumu korumuş oluruz. İlgili grubun başlığına tıklandığında açılma/kapanma durumunu tetikleyelim.
MasterPage’e tanımladığımız ListView kod bloğunda ItemTemplate şablonu içerisindeki th tagındaki tblname özniteliğini çaktırmadan tanımlamış oldum. Şimdi sıra javascipt tanımlamalarında. Aşağıdaki tanımlalar MasterPage sayfasının Head tagları arasında yapılmalıdır.
<script src="<%= GetAbsolutePath() %>Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
<script src="<%= GetAbsolutePath() %>Scripts/Plugins/jquery.highlight.js" type="text/javascript"></script>
<script src="<%= GetAbsolutePath() %>Scripts/Plugins/jquery.cookie.js" type="text/javascript"></script>
<script type="text/javascript">
$(document).ready(function () {
$(".DDGridView th").toggle(function () {
$.cookie("ak_" + $(this).attr("tblName"), "out");
var x = $(this).parent().parent().find(".jqMenutd").fadeOut("fast");
}, function () {
$.cookie("ak_" + $(this).attr("tblName"), "");
var x = $(this).parent().parent().find(".jqMenutd").fadeIn();
});
});
</script>
Bu işlemin ardından ekran görüntüsü aşağıdaki gibi olacaktır. Menü tarafı için artık yeter diyorum ve derin bir oh çekiyorum. Artık görünmesini yada yer kaplamasını istenmeyen kısımlar kullanıcıya özel olarak kısmen de olsa kapatılabiliyor. Ekran görüntüsü aşağıdaki gibi olmalıdır.

Bu yazı boyunca oldukca eğlendiğimi belirmek isterim. Herkese mutlu kodlar.
Ömer Faruk ZORLU
63e0f8a8-6bfd-4388-bd22-41a3bb715f72|0|.0