محتويات المقالة :- انشاء تطبيق ويب يتحكم بالبيانات باستعمال تقنية Dynamic Data دون الحاجة لكتابة أي كودات .- تعديل نموذج البيانات Data Model والمظهر الخارجي لتطبيق Dynamic Data.- اضافة مميزات Dynamic Data إلى تطبيقات الويب القديمة .يمضي اغلب المبرمجين كمية كبيرة من وقتهم الثمين في كتابة كودات تتعامل مع البيانات , واغلب هذا الوقت يضيع على العمليات الأساسية من انشاء وقراءة وتحديث وحذف للسجلات والبيانات من قاعدة البيانات.
فالإنشاء يعني عمل سطر جديد أو عنصر جديد وتخزينه في قاعدة البيانات . والقراءة تعني جلب قائمة بيانات من القاعدة وعرضها للمستخدم سواء كانت القائمة تشمل كل البيانات في القاعدة أو جزء منها حسب فلتر معين ويمكن أن تكون عنصر واحد فقط .
اما الحذف فهو عبارة عن ازالة سطر أو اكثر من العناصر في قاعدة البيانات . والتحديث يكون بوضع قيم جديدة لعنصر موجود سابقاً في القاعدة .
جميع هذه العمليات البرمجية يعرفها ويستخدمها كل المبرمجين والمطورين ويبرمجونها في مواقع الويب بلغات عدة كالphp و ASP.NET وClassic ASP . لكن الذي يميز Dynamic Data في ASP.NET بأنها اطار عمل framework تحفظ عليك كتابة هذا الكم الهائل من الكودات وتنشأ لك مواقع ذات تحكم كامل بالبيانات الموجودة في القاعدة بشكل تلقائي.
قد تقول أن هذا الأمر غير مهم ولن اتعب نفسي بتعلمه لأنني اعرف البرمجة التقليدية فاقول لك عزيزي المبرمج إن وقتك الثمين هو اهم ما تملك فبدلاً من أن تضيعه على كتابة كودات اساسية دائماً دع هذا الوقت لامور اخرى في برامجك مثل تحسين اداءها وزيادة مميزاتها ودع Dynamic Data تساعدك في تلك الأمور الاساسية في التعامل مع البيانات .
تذكر ايضاً أن الكودات الأقل في البرنامج تعني اقل عدد من الأخطاء الممكنة .
معلومة : تسمى الالية التي تستخدمها ASP.NET Dyamic Data لانشاء صفحات الويب بشكل ديناميكي اعتمادة على قاعدة بيانات تحتية بـ Scaffolding . تحتوي الصفحات المنشئة تلقائياً على جميع الوظائف والمميزات التي تتوقعها وتحتاجها مثل تقسيم الصفحات والترتيب اضافة إلى تزويد المطورين بامكانية تعديل كل الواجهة وكتابة كودات اضافية في حال تطلب الأمر لذلك . تزود Scaffolding المبرمجين بتحقق داخلي built-in validation مبني على النمط الموجود في قاعدة البيانات ويوجد ايضاً دعم كامل للforeign keys والعلاقات بين الجداول .الية Scaffolding هي الية مشهورة في Ruby on Rails وقد اضافتها مايكروسوفت لASP.NET Dynamic Data اضافة لعدة اليات ومبادئ اخرى مثل مبدأ تغليب العرف على الإعدادات والذي يعني أن الأشياء تفهم حسب العرف والتقاليد الإعتيادية . فمثلاً ستكتشف Dynamic Data في وقت التفيذ وجود ملف List.aspx ضمن مجلد يسمى Products وستستعمله لعرض صفحة ويب مخصصة لجدول Product في قاعدة البيانات . ولأن اسم المجلد هو نفس اسم الجدول في قاعدة البيانات (حتى لو كان بصيغة الجمع ) فلا حاجة لاخبار Dynamic Data أن هذا الملف موجود أو نربطه بجدول Product.
توضح لك هذه المقالة كيفية استعمال الية Scaffolding في Dynamic Data من اجل انشاء تطبيق ويب يتحكم بالبيانات دون الحاجة لكتابة أكواد (قد نحتاج لكتابة جزء يسير منها اثناء عملية التعديل) . سوف نرى ايضاً المرونة الكبيرة التي تقدمها Dynamic Data في تعديل نموذج عرض البيانات وصفحات الويب .
ومع أن Dynamic Data تبدو لك بأنها تحتاج لعمل كل ذلك من البداية إلا انك سترى في اخر هذه المقالة كيفية اضافة هذه التقنية الحديثة إلى تطبيقات ويب موجودة سابقاً دون الحاجة لاعادة عمله من جديد.
انشاء تطبيق ويب باستعمال Dynamic Data قبل أن ننشأ ونشغل تطبيق ويب مبني بDynamic Data فإننا نحتاج لقاعدة بيانات معينة حتى نطبق عليها .سوف نستعمل في الأمثلة المقدمة في هذه المقالة قاعدة بيانات SQL Server 2008 AdventureWorksLT والتي يمكنك تحميلها من codePlex على الرابط التالي :
http://msftdbprodsamples.codeplex.co...nloadId=106391عندما تحمل قاعدة البيانات افتح الفيجوال ستديو 2010 واختار File ثم New و Project بعدها قم باختيار اللغة البرمجية للمشروع اما C# أو فيجوال بيسك . سترى بعد ذلك ظهور قالبي مشروع رئيسيين للDynamic Data واللذان يمثلان الخيارات الأساسية المدعومة من مايكروسوفت للوصول للبيانات . القالب الأول هو LINQ to SQL واسمه يكون Dynamic Data Linq to SQL Web Application . اما القالب الثاني فهو Dynamic Data Entities Web Application الذي يدعم ADO.NET Entity Framework .
ملاحظة : اذا كنت تفضل العمل مع مشاريع Web Site بدلاً من مشاريع Web Application فيمكنك ايضاً استعمال Dynamic Data حيث انك ستجد تحت نافذة حوار Web Site قالبين مكافئين لانشاء مشروع LINQ to SQL أو مشروع Entities Dynamic Data للWeb Site .معلومة : الفرق بين LINQ to SQL و ADO.NET ENTITY FrameworkLINQ to SQL و ADO.NET ENTITY Framework هما الخيارين الأساسيين اللذين تقدمهما مايكروسوفت للوصول للبيانات . يوجد لكلا الخيارين محترفون ومستعملون وكلاهمها سيعملان بشكل ممتاز مع اغلب مواقع الويب .تعمل LINQ to SQL فقط مع قاعدة بيانات Microsoft SQL Server وتدعم فقط ربط مباشر لجدول واحد في قاعدة البيانات مع كلاس واحد في .NET . ولأن LINQ to SQL تمتلك علاقة قوية جداً مع SQL Server فهي تنتح كودات T-SQL ذات كفاءة عالية.اما على الناحية الاخرى فتسمح ADO.NET ENTITY Framework لنموذج البيانات Data Model بأن يكون مختلف عن شكل قاعدة البيانات . فيمكنك من ربط عدة جداول في الداتابيز مع كلاس .NET واحد ويمكنك ايضاً ربط جدول واحد في قاعدة البيانات مع عدة كلاسات في .NET .تدعم Entity Framework عدة انواع من قواعد البيانات ومن ضمنها Oracle و MySQL و DB2 .اختار مشروع Dynamic Data Linq to SQL Web Application واضغط OK.
عندما يتم انشاء المشروع الجديد سوف يتم انشاء عدد ضخم من الملفات والمجلدات كما هو مبين في الصورة التالية :
اغلب هذه الملفات هي عبارة عن قوالب يمكننا تعديلها لتغيير مظهر الصفحة والواجهة التي تظهر للمتسخدم . توجد هذه الملفات ضمن المجلد الرئيسي Dynamic Data وسوف نناقشها لاحقاً في هذه المقالة .
سوف يتم ايضاً اضافة صفحة Default.aspx والتي ستكون الصفحة الإبتدائية عند تشغيل المشروع .
وكأي مشروع ويب في ASP.NET فالتطبيق يقدم افضل الميزات عن طريق استعمال خواص صفحة ماستر وملف CSS خارجي ويتضمن مكتبة JQuery JavaScript .
اضافة نموذج بيانات Data Modelعندما انشأنا مشروعنا الجديد نحتاج فيه لتحديد قاعدة البيانات ومن ثم انشاء نموذج بيانات جديد . اضغط بالرز الأيمن على مجلد App_Data واختار Add Existing Item وبعدها ابحث عن قاعدة البيانات التي حملناها قبل قليل AdventureWorksLT2008_Data.mdf ثم اختارها واضغط Add .
الخطوة التالية هي انشاء نموذج بيانات Data Model ولعمل ذلك نضغط بالرز الأيمن على المشروع في Server Explorer ونختار Add وبعدها New Item واختار LINQ to SQL Classes ضمن فئة Data وسمه بـ AdventureWorksDM.dbml.
اذا كنت قد اخترت سابقاً Entities Dynamic Data عند انشاء المشروع فإنك تحتاج لاختيار ADO.NET Entity Data Model بدلاً من ذلك .
بعد أن تضغط Add سوف يتم فتح العنصر الجديد في المصمم Object Relational Designer. اضغط بشكل مزدوج على ملف قاعدة البيانات AdventureWorksLT (الذي اضفناه منذ قليل) في Server Explorer وبعد ذلك قم بعمل تمديد لخيار Tables وثم اختار جميع الجداول باستثناء اول اثنين واسحبهم إلى الDesigner . بهذا سوف يصبح نموذج البيانات Data Model مؤهلاً وجاهزاً كما في الصورة التالية :
سوف نحتاج في النهاية لتسجيل نموذج البيانات مع Dynamic Data وتفعيل Scaffolding ولعمل ذلك نفتح ملف Global.asax.cs ( أو Global.asax.vb اذا كنت تستخدم الفيجوال بيسك) وابحث عن مكان السطر التالي وازل التعليق عنه وغير YourDataContextType إلى AdventureWorksDMDataContext. وبعدها غير الproperty المسماة ScaffoldAllTables إلى true.
رمز Code:
C#
//انظر لملف Global.asax.cs
DefaultModel.RegisterContext(typeof(AdventureWorksDMDataContext),
new ContextConfiguration()
{ ScaffoldAllTables = true });
رمز Code:
VB
'انظر لملف Global.asax.vb
DefaultModel.RegisterContext(GetType(AdventureWorksDMDataContext), _
New ContextConfiguration() _
With {.ScaffoldAllTables = True})
إللى هنا نكون قد حصلنا على تطبيق ويب يتحكم بالبيانات وداعم للعمليات الرئيسية (اضافة وتعديل وحذف وعرض المعلومات).
عرض وتصفح تطبيق Dynamic Dataعندما تشغل التطبيق سوف يتم فتح الصفحة الرئيسية Default.aspx والتي تعرض روابط لجميع الجداول التي اضفتها لنموذج البيانات (انظر للصورة السابقة) لاحظ أن الأسماء المعروضة في هذه الصفحة هي عبارة عن اسماء الجداول لكنها بصيغة الجمع .
عندما تضغط على احد هذه الروابط سوف يأخذك لصفحة List.aspx للجدول المختار كما في الصورة التالية:
تمثل هذه الصفحة وصفحة Details (التي تعرض عنصر واحد مستقل) صفحات قراءة المحتويات الموجودة في قاعدة البيانات وتضمن دعم للpaging وفلترة المحتويات عن طريق foreign key . يوجد في هذه الصفحة ايضاً روابط لرؤية تفاصيل عنصر معين أو تعديله أو حذفه . تعرض الforeign key كروابط لصفحة التفاصيل المتعلقة بذلك الkey.
ملاحظة : لاحظ أن بعض حقول قاعدة البيانات غير موجودة في هذه الصفحة مثل ProductID و ThumbNailPhoto. وذلك لأن Dynamic Data لن تعمل Scaffold لاعمدة الIdentity أو binary أو الأعمدة المحوسبة ومع ذلك يمكنك عمل override لهذا الأمر كما سنرى لاحقاً في هذه المقالة .
يمكنك الوصول لميزة التعديل عن طريق الضغط على رابط Edit مقابل كل عنصر معروض وهذا سوف يأخذك لصفحة Edit.aspx كما هو مبين في الصورة التالية.
سوف تلاحظ أن صناديق النص textboxes تختلف اطوالها اعتماداً على طول الحقل في قاعدة البيانات .
تحتوي هذه الصفحة ايضاً على عدد من ادوات التحقق في ASP.NET اعتماداً على معلومات الحقل في قاعدة البيانات . فمثلاً يمتلك حقل ProductNumber التحقق RequiredFieldVlidator لأن الحقل المقابل له في قاعدة البيانات هو غير قابل لاحتواء قيمة null . اما حقل Weight فيستعمل CompareValidator حتى يتأكد أن القيمة المدخلة هي قيمة رقمية عشرية .
لاحظ أن الforeign keys موضوعة في قوائم , فمثلاً في الصورة السابقة حقول ProductCategory و ProductModel هي عبارة عن foreign keys وجميع الجداول التي تستعمل الجدول المختار كforeign key سوف تعرض كروابط . يمكن رؤية هذا الأمر في حقل SalesOrderDetails في نفس الصورة .
تعديل نموذج البيانات Data Modelمع أن الصفحات التي قمنا بانشائها هي جميلة ورائعة إلا أنها في واقع الأمر ليست كالتي تريد عملها فقد يكون هدفك عرض جدول معين أو اخفاء حقول معينة للمستخدمين . كل هذا واكثر يمكنك عمله في Dynamic Data عن طريق تعديل نموذج البيانات data model .
تعديل ظهور جداول معينةقبل أن نبدأ تعديل نموذج البيانات Data Model نحتاج لتعطيل الscaffolding لجميع الجداول . لذلك افتح ملف Global.asax.cs وغير الproperty المسماة ScaffoldAllTables إلى false.
الخطوة التالية هي اختيار الجداول المعينة التي تريد عرضها . بداية نضيف ملف كلاس جديد للمشروع نسميه Product.cs وهذا الكلاس يجب أن يكون كلاس جزئي partial class لأن Product معرف سابقاً في نموذج البيانات LINQ to SQL . حتى نفعل الscaffolding لجدول Product نقوم بوضع attribute جديد باسم ScaffoldingTables على الكلاس الذي انشأناه . وعندما ننتهي يجب أن يكون شكل الكلاس مشابهاً للتالي:
رمز Code:
C#
//انظر لملف Product.cs
using System.ComponentModel.DataAnnotations;
namespace DynDataWebApp
{
[ScaffoldTable(true)]
public partial class Product
{
}
}
رمز Code:
VB
'انظر لملف Product.vb
Imports System.ComponentModel.DataAnnotations
< ScaffoldTable(True) > _
Partial Public Class Product
End Class
اذا قمت بتشغيل التطبيق الان سوف تلاحظ أنه سيتم عرض جدول Product فقط وهو قابل للتعديل بطبيعة الحال.
ملاحظة : يمكنك الحصول على نفس النتيجة بالإبقاء على قيمة true للproperty المسماة ScaffoldingTables في ملف Global.asax.cs ثم وضع الattribute المسمى ScaffoldTables ل false في كلاسات الجداول التي تريد اخفاءها .
تعديل ظهور حقول معينة سوف نحتاج في بعض الأحيان إلى أن تكون بعض الحقول في الجدول قابلة للقراءة فقط أو مخفية وهذا الأمر سيكون مفيد في حال كان الجدول يحتوي على معلومات حساسة مثل بطاقات الإئتمان .
فمثلاً عندما تعدل عنصر في جدول Product سوف يعرف لك رابط لجدول SalesOrderDetails وهذا الرابط سيكون غير مفعل لأن الجدول SalesOrderDetails ليس ظاهر في العرض لذلك عرض هذا الحقل لن يعطي المستخدم أي معلومات مفيدة . وهناك ايضاً الحقل Modified Date فصحيح أنه مفيد للمستخدمين لكنك بطبيعة الحال قد لا ترغب في تعديله في صفحة التعديل لذلك الأفضل جعل هذا الحقل للقراءة فقط والسماح لقاعدة البيانات بتعديله عن طريق update trigger.
تستطيع عمل هذه الأمور في الDynamic Data عن طريق اضافة كلاس metadata إلى كلاس نموذج البيانات .
اضف كلاس جديد في اسفل ملف Product.cs وسميه كلاس ProductMetadat وقم بانشاء حقول public باسماء الحقول الموجودة في قاعدة البيانات والتي ترغب بتعديلها . ولأن Dynamic Data سوف تقرأ وتحدد نوع هذه الحقول من نموذج البيانات data model وليس من كلاس metadata لذلك تحديد نوعها لن يكون مهماً لذلك ضعها object.
اضف الattribute المسمى ScaffoldColumn إلى حقل SalesOrderDetails وضع القيمة false من اجل اخفاءه . اما لجعل الحقل ModifiedDate قابل للقراءة فقط نستعمل الattribute المسمى Editable ونضع قيمته لfalse.
توضح الكودات التالية التغييرات التي قمنا بها .
رمز Code:
C#
//انظر لملف Product.cs
namespace DynDataWebApp
{
[ScaffoldTable(true)]
[MetadataType(typeof(ProductMetadata))]
public partial class Product
{
}
public class ProductMetadata
{
[ScaffoldColumn(false)]
public object SalesOrderDetails;
[Editable(false)]
public object ModifiedDate;
}
}
رمز Code:
VB
'انظر لملف Product.vb
_
_
Partial Public Class Product
End Class
Public Class ProductMetadata
_
Public SalesOrderDetails As Object
_
Public ModifiedDate As Object
End Class
تعرض الصور التالية نتائج هذه التغييرات , فالصورة الاولى تبين صفحة التعديل الأصلية بجدول Product :
اما الصورة التالية فتبين صفحة التعديل الجديدة بعدما قمنا بتعديل نموذج البيانات data model .
اضافة قوانين تحقق معدلة Validation Rules
ذكرنا سابقاً أن Dynamic Data تحتوي على دعم داخلي لقوانين التحقق للمدخلات والتي تأخذها اعتماداً على شكل وتركيب قاعدة البيانات , فمثلاً اذا كان هناك حقل في قاعدة البيانات عبارة عن not nullable فسيتم اضافة RequiredFieldValidator إلى صفحة التعديل والإضافة .
قد يكون هناك احياناً بعض القوانين لشكل البيانات ليست مدعومة من قبل قوانين التحقق فمثلاً في الجدول Product تكون جميع القيم المخزنة في حقل ProductNumber تتبع نمط معين بحيث تبدأ دائماً بحرفين كبيرين متبوعين بشرطة . يمكن وضع هذا النمط على حقل ProductNumber عن طريق الattribute المسمى RegularExpression كما هو موضح في الكودات التالية :
رمز Code:
C#
//انظر لملف Product.cs
[ScaffoldTable(true)]
[MetadataType(typeof(ProductMetadata))]
public partial class Product
{
}
public class ProductMetadata
{
[RegularExpression("^[A-Z]{2}-[A-Z0-9]{4}(-[A-Z0-9]{1,2})?$",
ErrorMessage="Product Number must be a valid format")]
public object ProductNumber;
}
رمز Code:
VB
'انظر لملف Product.vb
_
_
Partial Public Class Product
End Class
Public Class ProductMetadata
ErrorMessage:="Product Number must be a valid format")> _
Public ProductNumber As Object
End Class
يوجد هناك ايضا attributes اخرى مثل Range (والذي يفيد لتحديد نطاق القيم للحقول الرقمية) و Required و StringLength تفيدك في تطبيق قيود على حقول معينة في نموذج البيانات data model بدون عمل ذلك في قاعدة البيانات نفسها .
ورغم أن هذه الattributes المستخدمة لعمل قوانين خاصة للتحقق هي مفيدة لكنها ليست شاملة لجميع الحالات . فمثلاً اذا ادخل المستخدم تاريخ لSellEndDate اقل من تاريخ SellStartDate فسوف يظهر عندنا خطأ في وقت التشغيل وليس خطأ في التحقق vlidator error وذلك بسبب وجود قيود في قاعدة البيانات على هذا الحقل.
تقدم لنا LINQ to SQL اثنتين من الmethods لكل حقل في نموذج البيانات data model ويتم استدعاء هذه الmethods خلال عملية التعديل .
تستدعى الميثود الأولى OnFieldNameChanging مبارة قبل أن يتغير الحقل . اما الميثود الثانية OnFieldNameChanged فتستدعى مباشرة بعد أن يتم التغيير للحقل .
يمكننا كتابة partial methods ملائمة في نموضج البيانات data model حتى نضع قوانين تحقق خاصة بنا .
يعرض الكود التالي قاننون للتحقق أن القيمة المدخلة في حقل SellEndDate ليست اقل من قيمة SellStartDate.
رمز Code:
C#
//انظر لملف Product.cs
[ScaffoldTable(true)]
[MetadataType(typeof(ProductMetadata))]
public partial class Product
{
partial void OnSellEndDateChanging(DateTime? value)
{
if (value.HasValue && value.Value < this._SellStartDate)
{
throw new ValidationException(
"Sell End Date must be later than Sell Start Date");
}
}
}
رمز Code:
VB
'انظر لملف Product.vb
_
_
Partial Public Class Product
Private Sub OnSellEndDateChanging(ByVal value As Nullable(Of DateTime))
If value.HasValue AndAlso value.Value < Me._SellStartDate Then
Throw New ValidationException( _
"Sell End Date must be later than Sell Start Date")
End If
End Sub
End Class
الصورة التالية تعرض قانون التحقق الذي وضعناه
تغيير نمط العرض للحقول
الطريقة الإفتراضية لعرض بعض أنواع البيانات تكون عادة بنمط غير مثالي . فمثلاً حقول StandardCost و ListPrice (والذين يستعملون نوع بيانات money في SQL) يتم عرضهم كأرقام من 4 منازل عشرية . اما حقول SellEndDate و SellStartDate (واللذين يستعملون نوع بيانات datatime في SQL) فيتم عرضهم بكلا شقيهم : الوقت والتاريخ مع أن الوقت ليس مفضل للعرض دائماً.
اولاً حتى نحدد نمط ظهور الحقول في واجهة العرض نضع الattribute المسمى DisplayFormat على الproperty المعنية في نموذج البيانات data model , وهذا الattribute يمتلك property تدعى DataFormatString والتي تقبل بأي نمط للstring في .NET .
يحتوي هذا الattribute ايضاً على عدد من الباراميترز الإضافية للتحكم بشكل الظهور ومن ضمنهم باراميتر HTMLEncode (والذي يستخدم اذا كان الحقل يجب أن يكون بصيغة HTML ) والباراميتر NullDisplayText والذي يضع النص الذي يجب أن يعرض في حال كانت القيمة null.
يوضح الكود التالي استخدام الattributes المدعو DisplayFormat .
رمز Code:
C#
//انظر لملف Product.cs
[DisplayFormat(DataFormatString="{0:C}")]
public object ListPrice;
[DisplayFormat(DataFormatString="{0:MMM d, yyyy}",
NullDisplayText="Not Specified")]
public object SellEndDate;
رمز Code:
VB
'انظر لملف Product.vb
< Display(Name:="List Price") > _
< DisplayFormat(DataFormatString:="{0:C}") > _
Public ListPrice As Object
< Display(Name:="Sell End Date") > _
< DisplayFormat(DataFormatString:="{0:MMM d, yyyy}",
NullDisplayText:="Not Specified") > _
Public SellEndDate As Object
ملاحظة : سوف يطبق نمط العرض بالوضع الطبيعي على صفحات القراءة فقط وحتى نطبقها على صفحات التعديل يجب أن نضع الproperty المدعوة ApplyFormatInEditMode إلى true في الattribute الذي استعملناه قبل قليل DisplayFormat.
قد لا ترغب ايضاً بعرض اسماء حقول قاعدة البيانات كما هي في واجهة العرض لذلك يمكنك اعطاءها اسماء كما تريد ولجميع الحقول . لعمل ذلك تحتاج لاستعمال الattribute المدعو Display من اجل التحكم باسم الحق وترتيب ظهوره في القائمة .يقبل هذا الattribute عدة باراميترز ومن ضمنها Name (المخصص لاسم الحقل) والباراميتر Order ( المخصص لترتيب مكان ظهور الحقل في الصفحة ).
لاحظ في الكودات التالية أننا قمنا باعطاء الحقل ProductNumber اسم ProductCode وتم اعطاءه رقم ترتيب 1 لكي نتأكد أنه يعرض كاول حقل في الصفحة .
رمز Code:
C#
//انظر لملف Product.cs
[Display(Name="Product Code", Order=1)]
public object ProductNumber;
رمز Code:
VB
'انظر لملف Product.vb
_
Public ProductNumber As Object
توضح الصورة التالية نتائج التغييرات التي قمنا بها .
تغيير مظهر العرض
كما ذكرنا سابقاً فقد لا تكون الصفحة الناتجة بالشكل الذي تريده بالضبط وقد وضحنا في القسم السابق كيفية تعديل عدد من جوانب نموذج البيانات data model للتحكم بكيفية عرض جداول وحقول قواعد البيانات .
تلك التعديلات في جميع الأحوال هي مجرد تعديلات بسيطة ويوجد الكثير من القيود على تغيير ما نريد . لكن لحسن حظنا فإن الDynamic Data تستعمل نظام قوالب قوي وغني جداً يمكنك تعديله بشكل كامل مما يعطيك تحكم كامل بالواجهة .
تخزن ملفات القوالب للDynamic Data ضمن عدة مجلدات فرعية في مجلد DynamicData والذي هو المجلد الرئيسي لتطبيق الويب . ولأن Dynamic Data تتبع مبدأ الأعراف اكثر من الإعدادات فليس هناك حاجة لتسجيل هذه الملفات يدوياً معها لكن يجب وضع كل نوع من القوالب في مجلد مخصص وسوف يقوم اطار العمل بتحديد مكان التخزين واسم ملف القالب من اجل تحديد وقت تحميله في runtime.
google_protectAndRun("ads_core.google_render_ad", google_handleError, google_render_ad);
قوالب الصفحة Page Templates
تستعمل قوالب الصفحة لتزويد المستخدمين بشكل افتراضي لعرض جدول ما في قاعدة البيانات . يتم تخزين قوالب صفحات الماستر في مجلد DynamicData\PageTemplates وتضيف به Dynamic Data قوالب الصفحات الرئيسية الخمس المتعلقة بعرض وتعديل البيانات .
- Details.aspx : صفحة قابلة للقراءة فقط وتعرض معلومات عنصر معين من جدول ما.
- Edit.aspx : صفحة قابلة للتعديل و تعرض معلومات عنصر معين من جدول ما.
- Insert.aspx : تسمح هذه الصفحة للمتسخدمين بادخال البيانات لجدول ما .
- List.aspx : تعرض هذه الصفحة معلومات جدول ما عن طريق grid view مع دعم للpaging والترتيب .
- ListDetails.aspx : تستعمل هذه الصفحة عندما يتم اعداد Dyamic Data بوضعية الصفحة المشتركة combined-page , حيث تصبح عمليات العرض والتعديل والإدخال كلها بنفس الصفحة .
يمكنك تفعيل هذه الوضعية عن طريق اتباع التعليمات الموجودة في ملف Global.asax .
يمكنك تعديل أي من هذه القوالب الإفتراضية في حال اردت تطبيق التعديل على جميع جداول قاعدة البيانات . او يمكنك عمل override لقوالب الصفحة الرئيسية عن طريق انشاء مجموعة من القوالب المعدلة لجدول ما .
تخزن قوالب الصفحة المعدلة ضمن مجلد DynamicData\CustomPages .
بالنظر لقاعدة بيانات AdventureWorksLT فإن جدول SalesOrderHeader هو مرشح جيد لتطبيق قالب معدل عليه .
نحتاج قبل انشاء القالب لتفعيل Scaffolding لهذا الجدول كما هو موضح بالكودات التالية
رمز Code:
C#
//انظر لملف SalesOrderHeader.cs
using System.ComponentModel.DataAnnotations;
namespace DynDataWebApp
{
[ScaffoldTable(true)]
public partial class SalesOrderHeader
{
}
}
رمز Code:
VB
'انظر لملف SalesOrderHeader.vb
Imports System.ComponentModel.DataAnnotations
_
Partial Public Class SalesOrderHeader
End Class
بعد ذلك نقوم بانشاء مجلد فرعي اسمه SalesOrderHeaders ضمن مجلد DynamicData\CustomPages . وهذا المجلد سوف يحتوي على القوالب المعدلة لجدول SalesOrderHeader .
قم بنسخ قالب List.aspx من مجلد DynamicData\PageTemplates وضع النسخة في مجلد DynamicData\CustomPages\SalesOrderHeaders .
ملاحظة : يجب أن يكون اسم المجلد الذي قمنا بانشائه لقوالب الصفحة المعدلة باسم صيغة الجمع لاسم الجدول في قاعدة البيانات إلا اذا كان نموذج البيانات data model الذي نستعمله يستخدم ADO.NET Entity Framework version 3.5 أو في حال تغيير الخيار الإفتراضي لPluralize أو Singularize للGenerated Object Names. وفي هذه الحالة يجب أن يكون اسم المجلد بنفس اسم الجدول .
اصبح لدينا الان نسخة اخرى مطابقة للكلاس بعد أن قمنا بنسخ القالب لذلك لن يتم ترجمة تطبيقك واسهل طريقة لحل هذه المشكلة هي تغيير الnamespace إلى أي قيمة مناسبة في ملف التصميم والcode-behind للقالب الجديد كما هو مبين في الكود التالي:
رمز Code:
C#
//انظر لملف DynamicData\CustomPages\SalesOrderHeaders\List.aspx
< %@ Page Language="C#" MasterPageFile="~/Site.master" CodeBehind="List.aspx.cs"
Inherits="DynDataWebApp._SalesOrderHeaders.List" % >
رمز Code:
//انظر لملف DynamicData\CustomPages\SalesOrderHeaders\List.aspx.cs
namespace DynDataWebApp._SalesOrderHeaders
{
public partial class List : System.Web.UI.Page
{
// Code snipped
}
}
رمز Code:
VB
'انظر لملف DynamicData\CustomPages\SalesOrderHeaders\List.aspx
< %@ Page Language="VB" MasterPageFile="~/Site.master" CodeBehind="List.aspx.vb"
Inherits="DynDataWebApp._SalesOrderHeader.List" % >
رمز Code:
'انظر لملف DynamicData\CustomPages\SalesOrderHeaders\List.aspx.vb
Namespace _SalesOrderHeader
Class List
Inherits Page
' Code Snipped
End Class
End Namespace
يمكنك الان تغيير القالب باي شكل يعجبك فمثلاً يمكنك تقليص عدد الأعمدة الظاهرة في صفحة List مع ابقاءها في صفحتي Edit و Insert . هذا المستوى من التعديلات يكون فقط عن طريق انشاء قالب خاص معدل للجدول .
وحتى نعمل هذا التعديل نحدد مكان كنترول الGrid view في List.aspx ونزيل تفعيل العرض التلقائي لجميع حقول البيانات عن طريق اضافة الproperty التالية :
رمز Code:
AutoGenerateColumns="False"
وبعدها نحدد الحقول التي نريد اظهارها عن طريق اضافة مجموعة من DynamicField Controls كما هو مبين في الكودات التالية .
[code]
انظر لملف DynamicData\CustomPages\SalesOrderHeaders\List.asp x
EnablePersistedSelection="True" AllowPaging="True"
AllowSorting="True" CssClass="DDGridView"
AutoGenerateColumns="False" RowStyle-CssClass="td"
HeaderStyle-CssClass="th" CellPadding="6">
HeaderText="Order Date" />
HeaderText="Ship Date" />
HeaderText="Sub Total" />
HeaderText="Tax Amount" />
HeaderText="Freight" />
There are currently no items in this table.
[code/]
توضح الصورة التالية مظهر List لجدول SalesOrderHeder مع تقليص عدد الأعمدة .
قوالب الحقول Field Templates
تستخدم قوالب الحقول لعمل عرض معين لحقول بيانات معينة وهناك قوالب للعرض واخرى للتعديل وتسمى قوالب الحقول بناءً على اسم نوع البيانات (ملحقة ب _Edit لصفحة التعديل) فمثلاً قالب العرض لحقل Text يسمى Text,ascx ويتم عرض الحقل باستعمال ASP.NET Literal control .
يحتوي قالب التعديل ايضاً على عدة Validation Controls مفعلة من نموذج البيانات وتعالج حدوث اي استثناء للتحقق من قبله .
تحتوي Dynamic Data على عدد ضخم من قوالب الحقول كما هو مبين في الصورة التالية .
يمكنك تعديل قوالب الحقول الإفتراضية أو انشاء قوالب جديدة مثل ما رأينا في قوالب الصفحة , و يتم تخزين قوالب الحقول ومن ضمنها القوالب الجديدة التي نقوم بانشائها في مجلد DynamicData\FieldTemplates .
يتم عرض عدة حقول بيانات من جدول SalesOrderHeader (الموجود في قاعدة AdventureWorksLT) مع الوقت والتاريخ مع العلم أن الوقت ليس ذو فائدة وكثير منا يرغب في ازالته .
يعرض قالب حقل DateTime في Dynamic Data كنترول TextBox بسيط في وضع التعديل . في حال اردت ادخال التاريخ فقط من الدون الوقت سيكون من الأفضل والأجمل أن تعرض كنترول Calender بدلاً من TextBox .
لعمل ذلك نبدأ بانشاء نسخة من قالب DateTime.ascx ونعيد تسميته إلى DateCalendar.ascx ثم نفتح ملفي التصميم والcode-behind لDateCalendar.ascx ونغير اسم الكلاس من DateTimeField إلى DateCalendarField كما هو مبين في الكودات التالية :
بعدها نأخذ نسخة من قالب DateTime_Edit.ascx ونغير اسمه إلى DateCalendar_Edit.ascx وكما فعلنا سابقاً نقوم بفتح ملفي التصميم والcode-behind لDateCalendar_Edit.ascx ونغير اسم الكلاس من DateTime_EditField إلى
DateCalendar_EditField كما في الكود التالي .
رمز Code:
C#
//انظر لملف DynamicData\FieldTemplates\DateCalendar.ascx
<%@ Control Language="C#" CodeBehind="DateCalendar.ascx.cs"
Inherits="DynDataWebApp.DateCalendarField" %>
رمز Code:
//انظر لملف DynamicData\FieldTemplates\DateCalendar.ascx.cs
namespace DynDataWebApp
{
public partial class DateCalendarField : FieldTemplateUserControl
{
// Code snipped
}
}
رمز Code:
VB
'انظر لملف DynamicData\FieldTemplates\DateCalendar.ascx
<%@ Control Language="VB" CodeBehind="DateCalendar.ascx.vb"
Inherits="DynDataWebApp.DateCalendarField" %>
رمز Code:
'انظر لملف DynamicData\FieldTemplates\DateCalendar.ascx.vb
Class DateCalendarField
Inherits FieldTemplateUserControl
' Code Snipped
End Class
لحد الان يمكننا استبدال كنترول الTextBox في ملف DateCalendar_Edit.ascx بكنترول الCalender لكن هذا الأمر يحتاج إلى بعض التغييرات في الcode-behind حتى يتم العمل مع الكنترول الجديد.
اسهل حل هو استعمال Calender control من AJAX Control Toolkit وهذا يسمى بControl Extender والذي يرتبط بالTextBox الموجودة ويضيف عليها مميزات اجاكسية .
يمكنك تحميل AJAX Control Toolkit من الرابط التالي :
http://ajaxcontroltoolkit.codeplex.com/
وبعد ذلك نقوم بتنصيبها للفيجوال ستديو 2010 عن طريق نسخ ملف AjaxControlToolkit.dll الى مجلد في منطقة جيدة في جهازك (حتى لا تخطأ وتمسحه مصادفة) وبعد ذلك نذهب للفيجوال ستديو 2010 وضغط بالزر الأيمن على نافذة الToolbox ونختار Add Tab واعطيها اي اسم له معنى وبعد ذلك اضغط بالزر الأيمن على الTab الجديد ونختار Choose Items وبعد ذلك نختار ملف AjaxControlToolkit.dll وبعدها ستلاحظ اضافة ادوات جديدة رائعة لصفحة الأدوات .
نضيف الكنترول Calender Extender على قالب DateCalendar_Edit.ascx وبعدها نضع الProperty المسماة TargetControlID و الProperty المسماة Format كما في الكود التالي:
رمز Code:
انظر لملف DynamicData\FieldTemplates\DateCalendar_Edit.ascx
Format="d-MMM-yyyy" runat="server">
يبقى عندنا خطوة اخيرة وهي ربط بعض الحقول في نموذج البيانات بقوالب الحقول الجديدة التي انشئناها وفي مثالنا هذا نحتاج لربط حقول OrderDate و ShipDate و DueDate من جدول SalesOrderHeader بتلك القوالب .
نعدل الكلاس الجزئي لSalesOrderHeader ونضيف كلاس metadata كما تعلمنا سابقاً . ثم نضع بعدها الattribute الذي يدعى UIHint من اجل ربط حقول معينة بقوالب الحقول المعدلة كما في الكودات التالية :
رمز Code:
C#
//انظر لملف SalesOrderHeader.cs
namespace DynDataWebApp
{
[ScaffoldTable(true)]
[MetadataType(typeof(SalesOrderHeaderMetadata))]
public partial class SalesOrderHeader
{
}
public class SalesOrderHeaderMetadata
{
[DisplayFormat(DataFormatString = "{0:dd-MMM-yyyy}",
ApplyFormatInEditMode = true)]
[UIHint("DateCalendar")]
public object OrderDate;
[DisplayFormat(DataFormatString = "{0:dd-MMM-yyyy}",
ApplyFormatInEditMode = true)]
[UIHint("DateCalendar")]
public object DueDate;
[DisplayFormat(DataFormatString = "{0:dd-MMM-yyyy}",
ApplyFormatInEditMode = true)]
[UIHint("DateCalendar")]
public object ShipDate;
}
}
رمز Code:
VB
'انظر لملف SalesOrderHeader.vb
_
_
Partial Public Class SalesOrderHeader
End Class
Public Class SalesOrderHeaderMetadata
ApplyFormatInEditMode:=True)> _
_
Public OrderDate As Object
ApplyFormatInEditMode:=True)> _
_
Public DueDate As Object
ApplyFormatInEditMode:=True)> _
_
Public ShipDate As Object
End Class
تعرض الصورة التالية قالب الحقل المعدل في صفحة التعديل لاحد العناصر في جدول SalesOrderHeader .
في حال لم تعمل معك يجب عليك ازالة الكنترول ScriptManager من صفحة Site.master والبحث عن كنترول ToolkitScriptManager من قائمة الأدوات الجديدة التي قمت باضافتها منذ قليل ومن ثم سحب هذا الكنترول ووضعه مكان الكنترول السابق.
قوالب العنصر Entity Templates
تستخدم قوالب العنصر من اجل عرض عنصر واحد من قاعدة البيانات وتخزن قوالب العنصر الإفتراضية في مجلد DynamicData\EntityTemplates وتضمن قوالب لانشاء وتعديل وعرض عنصر أو سجل واحد . تعمل هذه القوالب مع قوالب الصفحة الإفتراضية وتعرض UI باستعمال جدول HTML ذو عمودين , الأيسر للاسم والأيمن للبيانات .
تعديل قوالبن العنصر الموجودة سوف تؤثر على جميع الجداول . يمكنك ايضاً انشاء قالب معدل لجدول معين مما يسمح لك بعمل مخطط layout مختلف كلياً في حالة التعديل عنه في حالة العرض .
لانشاء قالب عنصر جديد نضغط بالزر الأيمن على مجلد DynamicData\EntityTemplate ونختار Add وثم New Item وبعدها نختار Web User Control وتعطيه اسم SalesOrderHeaders.ascx .
تستعمل القوالب الإفتراضية كنترول EntityTemplate والذي يكافئ تقريباً Repeater web server control . ينشأ هذا الكنترول جميع الحقول لهذا الجدول بشكل ديناميكي . يمكنك في هذه الحالة تحديد الحقول التي ترغب بعرضها بشكل يدوي بدلاً من استعمال كنترول EntityTemplate .
يعرض الكود التالي قالب عنصر معدل حيث يعرف مجموعة جزئية من البيانات .
رمز Code:
انظر للملف DynamicData\EntityTemplates\SalesOrderHeader.ascx
Acct No: DataField="AccountNumber" />
PO No: DataField="PurchaseOrderNumber" />
|
Ordered: DataField="OrderDate" />
Due: DataField="DueDate" />
Shipped: DataField="ShipDate" />
|
Sub Total: DataField="SubTotal" DataFormatString="{0:c}" />
Tax: DataField="TaxAmt" DataFormatString="{0:c}" />
Freight: DataField="Freight" DataFormatString="{0:c}" />
|
اخر خطوة نقوم بتغيير الweb server control حتى يشتق من System.Web.DynamicData.EntityTemplate UserControl بدلاً من System.Web.UI.UserControl
رمز Code:
C#
//انظر لملف DynamicData\EntityTemplates\SalesOrderHeader.ascx.cs
public partial class SalesOrderHeaders :
System.Web.DynamicData.EntityTemplateUserControl
رمز Code:
VB
'انظر لملف DynamicData\EntityTemplates\SalesOrderHeader.ascx.vb
Public Class SalesOrderHeaders
Inherits System.Web.DynamicData.EntityTemplateUserControl
تستطيع الان بناء وتشغيل المشروع لتجريب قالب العنصر الجديد.
توضح الصورة التالية كل القالب الإفتراضي للعنصر
بينما الصورة التالية توضح شكل الصفحة بعد تعديل القالب لجدول SalesOrderHeader .
لاحظ أن صفحات التعديل Edit والإضافة Insert لم تتغير وذلك لأن القالب الذي تم تعديله هو قالب عرض التفاصيل فقط .
قوالب الفلتر
تستعمل قوالب الفلتر لعرض كنترول يقوم بفلترة الصفوف المعروضة لجدول ما . يوجد في Dynamic Data ثلاثة قوالب للفلاتر المخزنة في مجلد DynamicData\Filters واسمائها واضحة .
يستخدم الفلتر Boolean لانواع البيانات المنطقية اما فلتر Enumeration فيستخدم في حال كان نوع البيانات مربوط بenum اما فلتر Foreign key فيستخدم لعلاقات الforeign.
تعرض الصورة التالية قوالب الفلاتر الأربعة التي تعرض بشكل تلقائي لجدول SalesOrderHeader .
الفلتر الأول "OnlineOrderFlag" هو فلتر من نوع Boolean يحتوي على ثلاثة خيارات : ALL و True و False . اما الفلاتر الثلاثة الاخرى فقد تم توليدها من الforeign keys وكل منها يمتلك عدد كبير من العناصر .
ملاحظة : ربما قد لاحظت أن القيم المعروضة في قائمة Customer هي ببساطة وصف الزبون (Mr و Mrs وهكذا ..) والتي هي عديمة الفائدة .
عندما تجد Dynamic Data أن الحقل الأول في الجدول هو من نوع string سوف تختار هذا الحقل ليعرض في الforeign keys ويمكن عمل override لهذا الأمر لكي نختار حقل اخر في الجدول عن طريق وضع الattribute المسمى DisplayColumn على كلاس الdata model . الذي نحتاجه هنا في جدول Customer هو عرض string يحتوي على عدد من الحقول (FirstName و LastName ) ولعمل ذلك عليك ببساطة عمل override للميثود ToString() في كلاس Customer data model .
القوائم المنسدلة تكون عادة مفيدة في حال كانت تحتوي على عدد من العناصر لا يتجاور ال100 اما اذا كان هناك عدد اكبر فستصبح صفحة الويب بطيئة نسبياً ويصعب تصفح تلك القوائم .
فكلما زاد عدد الزبائن في قاعدة البيانات إلى الالاف أو اكثر فستصبح القوائم المنسدلة للforeign keys التي لدينا مثل Adress و Address1 و Customer غيرقابلة للاستعمال مع وجود امكانية لعرض الصفحة .
تحتاج لعمل شيئ متقدم اذا ما ادرت ابقاء هذه الفلاتر مثل تعديل فلتر foreignkey الإفتراضي مع كنترول search والذي يعمل على اعادة الإتصال بالسيرفر ويعرض قائمة تحتوي على عناصر تطابق الsearch . كل هذا يتم ضمن AJAX طبعاً.
يمكنك التدرب لوحدك على هذا الأمر حتى تكتسب خبرة اضافية .
ملاحظة : الشرح المتبقي في هذا القسم يفترض انك قد قمت بانشاء قالب صفحة معدل لجدول SalesOrderHeader كما وضحنا سابقاً في هذه المقالة .
نفتح القالب المعدل لList.aspx الخاص بجدول SalesOrderHeader من مجلد DynamicData\CustomPages\SalesOrderHeaders ونبحث عن كنترول QueryableFilterRepeater في هذه الصفحة .
يستخدم هذا الكنترول لتوليد قائمة من الفلاتر بشكل ديناميكي . لذلك سنقوم بحذف هذا الكنترول ونضيف مكانه كنترول DynamicFilter كما هو مبين في الكود التالي.
رمز Code:
انظر ملف DynamicData\CustomPages\SalesOrderHeader\List.aspx
Online Order:
DataField="OnlineOrderFlag" FilterUIHint="Boolean"
OnFilterChanged="DynamicFilter_FilterChanged">
لاحظ أنه يجب وضع قيمة الproperty المسماة DataField باسم حقل البيانات للفلتر , ويجب وضع قيمة الproperty المسماة FilterUIHint باسم قالب الفلتر الصحيح .
بعد ذلك نبحث عن كنترول QueryExtender في اسفل الصفحة والذي يستخدم لربط كنترول DynamicFilter مع مصدر البيانات data source لذلك سيتم استخدام الاستعلام الصحيح عندما يتغير الفلتر . الان نقوم بتعديل الproperty المسماة ControlID وضع اسم كنترول DynamicFilter الذي قمت باضافته قبل قليل كما هو مبين في الكود التالي:
رمز Code:
انظر ملف DynamicData\CustomPages\SalesOrderHeader\List.aspx
runat="server" >
تحتاج في النهاية إلى ازالة بعض الكودات التي كانت محتاجة فقط من قبل كنترول QueryableFilterRepeater وحتى نعمل ذلك نفتح ملف الcode-behind الذي يسمى (List.aspx.cs أو List.aspx.vb) ومن ثم قم بازالة ميثود Label_PreRender . وبعدها تشغل المشروع بعد أن تحفظ التغييرات وسوف ترى فلتر واحد فقط معروض لجدول SalesOrderHeader كما هو مبين في الصورة التالية.
تفعيل Dynamic Data للمشاريع الموجودة
Dynamic Data هي بلا شك طريقة قوية جداً لانشاء تطبيقات الويب التي تتحكم بالبيانات وقد جاءتنا مع اصدار Visual Studio 2010 ومع هذا فيمكنك استعمال مميزاتها في أي مشروع سابق لWeb Site أو Web Application .
نستعمل الميثود الإمتدادية EnableDynamicData من اجل تفعيل هذه الخاصية ويمكن لهذه الميثود أن تستدعى على أي كلاس يعمل implement للانترفيس System.Web.UI.INamingContainer وهذا يتضمن عدة controls مثل Repeater و DataGrid و DataList و CheckBoxList و ChangePassword و LoginView و Menu و SiteMapNodeItem و RadioButtonList.
اضافة Dynamic Data لأي web control موجود لا تحتاج أن يكون التطبيق يستعمل LINQ to SQL أو Entity Framework مما يسمح للتطبيقات المبنية بADO.NET القديمة ان تتمتع بالمميزات الجديدة التي تقدمها ASP.NET Dynamic Data وذلك لأن مميزات Dynamic Data التي تفعل بهذه الطريقة لاتحتاج إلى أي من وظائف Scaffolding . فبدلاً عن ذلك فهي تفعل قوالب الحقل والتحقق Validation وتعرض الattributes التي ناقشناها سابقاً في هذه المقالة .
فمثلاً حتى تفعل الDynamicData على كنترول GridView فإننا نستدعي الميثود الإمتدادية EnableDynamicData كما هو مبين في الكودات التالية .
رمز Code:
C#
GridView1.EnableDynamicData(typeof(Product));
رمز Code:
VB
GridView1.EnableDynamicData(GetType(Product))
يمكنك الان انشاء كلاس Product يحتوي على public properties تقابل البيانات المعروضة في GridView1 وكل من هذه الproperties يمكن وضع الattributes عليها من الnamspace التي تسمى : System.ComponentModel.DataAnnotations مثل Required و StringLength و RegularExpression و DisplayFormat .
سوف تقوم ASP.NET بترجمة هذه الattributes اثناء وقت التشغيل وتطبق التحقيقات والأنماط المتعلقة بشكل تلقائي مما يسمح لأي تطبيق بأن يدعم DynamicData دون الحاجة لعمل أي تعديلات مهمة على التطبيق .
خلاصة المقالة
تعلمنا في هذه المقالة كيفية استعمال ASP.NET Dynamic Data من اجل انشاء تطبيقات ويب تتحكم بالبيانات باستخدام كودات قليلة جداً (او حتى بدون استخدام اي كود).
الأمر المهم هو أننا رأينا المرونة التي تقدمها Dynamic Data عن طريق تعديل نموذج البيانات Data Model وصفحات الويب .
توفر Dynamic Data كثير من الوقت على المطورين اثناء عملية البرمجة مما يقلص الوقت الإجمالي للتطوير مما يتيح للمبرمجين امكانية اضافة مميزات اخرى للمستخدمين .
ملفات المشروع كاملة :
http://www.4shared.com/file/sAVM7Ze5/DynDataWebApp.html
عبد العظيم بخاري
http://www.el-bukhari.com/2010/01/dy...pnet-2010.html
الأحد يوليو 07, 2013 7:49 pm من طرف medhat
» انفراد :Winamp 5.57 Build 2765 Beta+SeriaL:افضل برامج تشغيل الصوت فى اخر اصدارته بحجم 14 ميجا
الأربعاء أبريل 10, 2013 6:55 am من طرف ماهر الريس
» قران رابسو
الخميس سبتمبر 13, 2012 2:58 pm من طرف medhat
» رجيم رمضان سهل
الأحد يوليو 22, 2012 1:50 pm من طرف saharamar
» جدول العبادات فى رمضان
الأحد يوليو 22, 2012 1:07 pm من طرف saharamar
» أمور تتثير أعجاب الرجل بزوجته بالحلال
السبت يونيو 30, 2012 7:29 pm من طرف saharamar
» دعاء انصح كل زوجة مخلصة ومحبة لزوجها ان تدعو به
السبت يونيو 30, 2012 7:21 pm من طرف saharamar
» أحلى صفات المرأة والتى تجعل الرجل يحبها بجنون
السبت يونيو 30, 2012 7:12 pm من طرف saharamar
» لا تنتظر الحب
الجمعة يونيو 22, 2012 9:30 pm من طرف saharamar