تقييم الموضوع :
  • 2 أصوات - بمعدل 5
  • 1
  • 2
  • 3
  • 4
  • 5
العلاقات بين الجداول-الاضافة و الحذف و التعديل-برنامج لحفظ مصادر الموقع
#1
السلام عليكم و رحمة الله و بركاته

قد يبدو الموضوع مكررا الى حد ما
نظرا لكثرة الطلبات الخاصة بمثل هذه المشاريع و خصوصا معالجة الاضافة و الحذف و التعديل في الجداول المرتبطة بعلاقات فان الموضوع يحتاج الى نقاشات كثيرة و شروحات معمقة.
الموضوع في اغلبه يخص المبتدئين اكثر لذلك اود المناقشة في الطريقة التقليدية بعيدا عن الطرق الحديثة في التعامل مع قواعد البيانات .
سبب طرح الموضوع هو فكرة برنامج لحفظ محتويات المقالات و المواضيع المهمة في اي موقع ترى فيه فائدة من مواضيعه و تخزينها في قاعدة بيانات مع جلب المرفقات الخاصة بكل موضوع و تخزينها ضمن مجلد البرنامج و ربطها بالموضوع المخزن في القاعدة (سيتم مناقشة هذه الجزئية لاحقا)
في البداية سنناقش طريقة تصميم القاعدة و ربطها مع لغة البرمجة بطريقة الكود مع الاستفادة من كل الكائنات الجاهزة في اللغة توفيرا لكتابة الكود و الحصول على افضل اداء 
اولا تصميم القاعدة.
ستحتوي على مجموعة من الجداول ساوضحها هنا بالصور

الجدول الاول جدول الاصناف Kind و بنيته كما في الصورة التالية




الجدول الثاني هو جدول الفروع Poster سيحتوي على الفروع المشتقة من الاصناف Kind


الجدول الثالث هو جدول المواضيع او المقالات Info  وهو يحتوي على كل المواضيع التي تندرج تحت فرع معين Poster



الجدول الرابع هو جدول الاكواد و هو جدول Coder يختص بتخزين الاكواد فقط المندرجة تحت صنف معين Kind




الجدول الخامس هو جدول المرفقات Attaches و هي للمرفقات في كل موضوع يتم تخزينه حيث لديك الامكانية لتخزين المرفقات مثل الملفات المضغوطة التي
توضع كمثال على المقالة او الشرح حيث يخزن فيه فقط اسم المرفق و مسار تخزينه في مجلد التخزين المرافق للبرنامج و يتم عرض الملفات المرفقة
المصاحبة لكل موضوع في قائمة ترتبط مع كل مقال مع امكانية فتح المرفق من واجهة البرنامج




الجدول السادس LoginsTb وهو جدول خاص بتخزين المواقع المفضلة لديك او بمعنى اخر المواقع التي انت عضو فيها و تحتاج الى تحميل صفحات منها او مرفقات بعد تسجيل الدخول
يحتوي على مجموعة من الحقول مثل اسم المستخدم و كلمة المرور و رابط الدخول للموقع و بارمترات الدخول اللازمة و كذلك بعض الحقول التي ستعرف عملها لاحقا عند البدء في شرح البرنامج و التعامل معه بشكل فعلي
وجب التنويه ان هذا الجدول مرتبط بشكل فعلي مع اعدادت البرنامج (نموذج الاعدادات الذي سيرد لاحقا)




تخطيط العلاقة بين الجداول في القاعدة و هو للعرض فقط لمعرفة سيناريو الربط بين الجداول اذا اننا سنقوم بالربط من خلال الكود




بعض الادخالات في واجهة البرنامج (اعدادات البرنامج) سنحتاجها خلال عملنا  اذا 
انها مطلوبة لتمكين الدخول الى المواقع المحمية باسم مستخدم و كلمة مرور 
هذه الاعدادت مرتبطة بنموذج داخل البرنامج لتمكين تغير الاعدادت حسب الموقع المراد الدخول اليه
و ساشرح الحاجة اليها وفق ورودها




النموذج الخاص بادخال الموقع الافتراضي مع الحقول اللازمة (اسم المستخدم و كلمة المرور) و البارمترات اللازمة لتمريرها مع طلب الدخول و المصادقة ثم الدخول
الشاشة سهلة جدا و تمكنك من فرض الدخول التلقائي الى اي موقع مسجل فيه بمجرد تعين الموقع كافتراضي ساشرحها لاحقا مع بدء الغوص في البرنامج



 
نموذج اول لتخزين الاكواد المنبثقة من كل صنف و هو نموذج جانبي لم اكن ارد تضمينه لكن شاء الله و قدر..
 تم استخدام مربع نص خاص لعرض الاكواد وفق طريقة لغات البرمجة و هو مضمن في مكتبة مرفقة بالبرنامج 
كنت اود استخدام شجرة البيانات لعرض التفريعات بشكل شجري لكن شيئ جعلني اتريث في استخدامها حتى تكتمل كل الافكار 
ربما استخدمها لاحقا في نموذج جديد للعرض فقط .
ملاحظة تم استخدام TableLayoutPanel للقيام بعمليات التحجيم التلقائي لعناصر النموذج.


 
هذا هو النموذج الرئيسي الخاص بالبرنامج يحتوي على الاصناف و التفريعات و المواضيع و المرفقات ايضا
 كما و يحتوي على مستعرض ويب داخله للدخول الى الموقع الذي تريده و كذلك لعرض المواضيع المخزنة
لديك في القاعدة
فقط ضع رابط الدخول ثم ادخل الى الموقع (طبعا اذا كنت عضو في الموقع وجب عليك ادخال البيانات في نموذج الاعدادات السابق) و هو سيتكفل بادخالك كعضو 
اذا كنت عضو فعلا في الموقع
كانت هناك مشكلة بالنسبة لعملية توريث الكوكيز للمتصفح و الحمد لله تم حلها ببعض دوال API و هي الان تعمل بشكل جيد
بالنسبة لعملية تحميل المرفقات مع المواضيع تتم في اسفل الشاشة عبر زر Download بالنسبة لاغلب المواقع يتم التحميل بشكل طبيعي اذا تمت المصادقة على دخولك
لكن بقيت لدي مشكلة لم اصل لحل لها في بعض المواقع اذا ان الخادم يرسل لي طول حجم غير حقيقي للملف المراد تحميله كحال موقع Codeproject
ساحاول حلها لاحقا ان شاء الله




 يتبع.........
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
الرد }}}
#2
بسم الله الرحمن الرحيم 
نكمل ما بدأناه سابقا
سنحاول ان نفصل اكواد الاتصال و الحفظ في كلاس منفصل 
سيكون لدي Module اسمه Connect
و نبدء باستيراد مجالات الاسماء و تعريف المتغيرات اللازمة لاجراء عملية الاتصال و كذلك الكائنات اللازمة لنقل البيانات و حفظها من و الى القاعدة

في اعلى Module المسمى Connect

كود :
Imports System.Data
Imports System.Data.OleDb
 
استوردنا المجالات اللازمة للتعامل مع قاعدة البيانات من النوع Access 

الان داخل Module نعرف الكائنات التالية


كود :
Module Connect
   Public ConnectionString As String = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=|DataDirectory|\Coder.accdb"
   Public Con As New OleDbConnection(ConnectionString)
   Dim KindDa, CodeDa, InfoDa, PostDa, AttachDa, LoginDa As New OleDb.OleDbDataAdapter
   Dim ComBulder1, ComBulder2, ComBulder3, ComBulder4, ComBulder5, ComBulder6 As New OleDbCommandBuilder
   Public MyDataset As New DataSet
   Private LoginDataSet As New DataSet
- السطر الاول هو مسار قاعدة البيانات داخل البرنامج و اسمها Coder
- السطر الثاني كائن اتصال ليؤمن لنا عملية فتح و اغلاق الاتصال مع قاعدة البيانات
- السطر الثالث مجموعة من كائنات DataAdapter سوف نستخدمها لنقل البيانات من و الى القاعدة كل واحد منها لجدول و يتضح ذلك عبر اسمائها
- السطر الرابع مجموعة من كائنات CommanBuilder سنستخدمها لتقوم بعمليات توليد جمل الادخال و التعديل و الحذف لكل جدول بدل من كتابة و تكرار جمل
  الادخال , هذا الكائن سحري في التعامل مع قواعد البيانات .
- السطر الخامس حاوية البيانات (قاعدة بيانات مؤقتة) سنستخدمها لنضيف اليها الجداول السابقة.
- السطر السادس حاوية بيانات اخرى فقط لجدول LOgins السابق ذكره.

ساقوم بعدها بانشاء بعض Functions التي تسهل علينا العمل 

كود :
   'جدول الانواع
   Private Function LoadKindTable() As DataTable
       Dim SelectField As String = "Select Id,Kind,Not1 From Kind"
       KindDa = New OleDbDataAdapter(SelectField, ConnectionString)
       KindDa.MissingSchemaAction = MissingSchemaAction.AddWithKey
       KindDa.MissingMappingAction = MissingMappingAction.Passthrough
       KindDa.Fill(MyDataset, "kind")
       Return MyDataset.Tables("Kind")
   End Function

 كما تلاحظ دالة بسيطة تعيد لي جدول بيانات الانواع , تحتوي على جملة تحديد مجموعة سجلات من الجدول 
ثم يقوم ناقل البيانات KindDa وفق الاتصال الممنوح له بجلب البيانات ووضعها في جدول في حاوية البيانات
لاحظ اننا فرضنا شروطا على هذا الناقل بان يقوم يقوم بتوريث مخطط الجدول الى حاوية البيانات و كذلك
فرض مفتاح اساسي في حال وجد في بنية الجدول المنقول.
اذ ستحتوي حاوية البيانات Mydataset على نفس اسم الجدول و كذلك على نفس اسماء الاعمدة في الجدول الاصل 
بنفس التخطيط هذا السطر هو المسؤول عن العملية

كود :
       KindDa.MissingMappingAction = MissingMappingAction.Passthrough

اما السطر الاخر فهو سيفرض مفتاح رئيسي في الجدول على على الحقل ذو القيد PrimaryKey و هو هنا Id

كود :
       KindDa.MissingSchemaAction = MissingSchemaAction.AddWithKey

سنكرر العملية لكل جدول نريد التعامل معه كما يلي

جدول الاكواد
كود :
   'جدول الاكواد
   Private Function LoadCodeTable() As DataTable
       Dim SelectField As String = "Select Id2,Not1,Not2,Code1,Code2,Kind_id From coder"
       CodeDa = New OleDbDataAdapter(SelectField, ConnectionString)
       CodeDa.MissingSchemaAction = MissingSchemaAction.AddWithKey
       CodeDa.MissingMappingAction = MissingMappingAction.Passthrough
       CodeDa.Fill(MyDataset, "Coder")
       Return MyDataset.Tables("Coder")
   End Function

جدول المواضيع او المقالات
كود :
   'جدول المقالات
   Private Function LoadInfoTable() As DataTable
       Dim SelectField As String = "Select IdInfo,Infoname,Content,UrlInfo,Id_Kind From Info"
       InfoDa = New OleDbDataAdapter(SelectField, ConnectionString)
       InfoDa.MissingSchemaAction = MissingSchemaAction.AddWithKey
       InfoDa.MissingMappingAction = MissingMappingAction.Passthrough
       InfoDa.Fill(MyDataset, "Info")
       Return MyDataset.Tables("Info")
   End Function

جدول الفروع
كود :
   'جدول الفروع
   Private Function LoadposterTable() As DataTable
       Dim SelectField As String = "Select id_post,poname,id_k From poster"
       PostDa = New OleDbDataAdapter(SelectField, ConnectionString)
       PostDa.MissingSchemaAction = MissingSchemaAction.AddWithKey
       PostDa.MissingMappingAction = MissingMappingAction.Passthrough
       PostDa.Fill(MyDataset, "post")
       Return MyDataset.Tables("post")
   End Function

جدول المرفقات
كود :
   'جدول المرفقات
   Private Function LoadAttachTable() As DataTable
       Dim SelectField As String = "Select  Attach_Id,AttachName,AttachPath,Id_inf From Attaches "
       AttachDa = New OleDbDataAdapter(SelectField, ConnectionString)
       AttachDa.MissingSchemaAction = MissingSchemaAction.AddWithKey
       AttachDa.MissingMappingAction = MissingMappingAction.Passthrough
       AttachDa.Fill(MyDataset, "Attach")
       Return MyDataset.Tables("Attach")
   End Function

جدول المواقع
كود :
   'جدول المواقع
   Private Function LoadLoginTable() As DataTable
       Dim SelectField As String = "Select Login_Id,SiteName,LoginUrl,usernamee,Passworde,ActionStr,formParams,Inputpass,Inputuser,InputAction From LoginsTb"
       LoginDa = New OleDbDataAdapter(SelectField, ConnectionString)
       LoginDa.MissingSchemaAction = MissingSchemaAction.AddWithKey
       LoginDa.MissingMappingAction = MissingMappingAction.Passthrough
       LoginDa.Fill(LoginDataSet, "LoginsTb")
       Return LoginDataSet.Tables("LoginsTb")
   End Function

بعد ذلك سنقوم بعمل اجراء خاص لفرض العلاقات بين الجداول و نقوم باضافته الى حاوية البيانات MyDataset 
تابع الكود التالي
كود :
   'فرض العلاقات
   Private Sub LoadRelation()
       If MyDataset.Tables.Contains("Kind") And MyDataset.Tables.Contains("Coder") And MyDataset.Tables.Contains("Info") And MyDataset.Tables.Contains("post") Then
           'علاقة1
           Dim KIndColumn As DataColumn = MyDataset.Tables("Kind").Columns("Id")
           'علاقة2
           Dim CoderColumn As DataColumn = MyDataset.Tables("Coder").Columns("Kind_id")
           Dim postidColumn As DataColumn = MyDataset.Tables("post").Columns("id_post")
           'علاقة3
           Dim postColumn As DataColumn = MyDataset.Tables("post").Columns("id_k")
           Dim InfoColumn As DataColumn = MyDataset.Tables("Info").Columns("Id_Kind")
           'علاقة4
           Dim InfoIdColumn As DataColumn = MyDataset.Tables("Info").Columns("IdInfo")
           Dim AttachColumn As DataColumn = MyDataset.Tables("Attach").Columns("Id_inf")

           'مسح العلاقات ان وجدت
           If MyDataset.Relations.Contains("Kind_Coder") Then
               MyDataset.Relations.Remove("Kind_Coder")
           End If
           '
           If MyDataset.Relations.Contains("Kind_post") Then
               MyDataset.Relations.Remove("Kind_post")
           End If
           '
           If MyDataset.Relations.Contains("Kind_Info") Then
               MyDataset.Relations.Remove("Kind_Info")
           End If
           '
           If MyDataset.Relations.Contains("Info_Attach") Then
               MyDataset.Relations.Remove("Info_Attach")
           End If

           'علاقة الانواع بالاسئلة و الاكواد
           Dim Relation1 As New DataRelation("Kind_Coder", KIndColumn, CoderColumn)
           MyDataset.Relations.Add(Relation1)
           MyDataset.Relations("Kind_Coder").ChildKeyConstraint.UpdateRule = Rule.Cascade
           MyDataset.Relations("Kind_Coder").ChildKeyConstraint.DeleteRule = Rule.Cascade

           'علاقة الانواع بالفروع
           Dim Relation2 As New DataRelation("Kind_post", KIndColumn, postColumn)
           MyDataset.Relations.Add(Relation2)
           MyDataset.Relations("Kind_post").ChildKeyConstraint.UpdateRule = Rule.Cascade
           MyDataset.Relations("Kind_post").ChildKeyConstraint.DeleteRule = Rule.Cascade

           'علاقة الفروع بالمقالات
           Dim Relation3 As New DataRelation("Kind_Info", postidColumn, InfoColumn)
           MyDataset.Relations.Add(Relation3)
           MyDataset.Relations("Kind_Info").ChildKeyConstraint.UpdateRule = Rule.Cascade
           MyDataset.Relations("Kind_Info").ChildKeyConstraint.DeleteRule = Rule.Cascade

           'علاقة المقالات بالمرفقات
           Dim Relation4 As New DataRelation("Info_Attach", InfoIdColumn, AttachColumn)
           MyDataset.Relations.Add(Relation4)
           MyDataset.Relations("Info_Attach").ChildKeyConstraint.UpdateRule = Rule.Cascade
           MyDataset.Relations("Info_Attach").ChildKeyConstraint.DeleteRule = Rule.Cascade

       End If
   End Sub

الكود بسط جدا ان شاء الله و ساشرحه هنا
  1. في البداية انا افحص تواجد الجداول داخل Dataset .
  2. بعدها اقوم بتعريف الاعمدة التي ستقوم بعمليات الربط (المفتاح الرئيسي و المفتاح الثانوي).
  3. ثم نقوم بمسح العلاقات من Dataset ان وجدت.
  4. بعدها نقوم بتعريف كائن العلاقة بين جدولين و نسندله المفتاحين في الاب و الابن و نعطي اسم للعلاقة.
  5. نضيف العلاقة لكائن Dataset .
  6. ثم نقوم بفرض شرط على العلاقة ان تقوم بعمليات التحديث و الحذف بشكل متزامن بين الجدول الاب و الجدول الابن.
هذا كل ما في الامر بالنسبة لفرض العلاقة.

بعد ذلك سنقوم بعمل دالة Function تعيد لنا كائن Dataset معبئ بالجداول و العلاقات كما نحب و نشتهي
كود :
   Public Function LoadDataSet() As DataSet
       LoadKindTable()
       LoadCodeTable()
       LoadposterTable()
       LoadInfoTable()
       LoadAttachTable()
       LoadRelation()
       '
       Return MyDataset
   End Function
 
اضن الكود سهل الهضم و لا يحتاج شرح فهو تجميع للدوال السابقة.

الان ناتي الى اجراء الحفظ الخاص بكل ما جرى على الجداول من حذف و اضافة و تعديل
السيناريو الذي ستعمل معه هو تفحص تغير سجلات القاعدة المؤقته (MyDataset
و نؤخذ نسخة من كل السجلات التي تعرضت للاضافة او التعديل او الحذف و نرحلها الى قاعدة مؤقته جديدة ساسميها SaveDataset
تحتوي فقط على السجلات المحدثة(مضاف-معدل-محذوف)
ثم سنقوم بارسال التحديثات الى القاعدة الاصل (Access Database
و بعد الحصول على التحديثات من القاعدة سنقوم بدمج Mydataset مع SaveDataset
وقبول التغيرات الحاصلة .
طريقة سهلة و واضحة و قوية و هي لب الاتصال المنفصل
لنرى ذلك عبر الكود اللذيذ مع الشرح 

كود :
   Public Sub SaveData()
       Try
           Dim SaveDataset As New DataSet
           SaveDataset = MyDataset.Clone

           If MyDataset.HasChanges = True Then
               SaveDataset = MyDataset.GetChanges(DataRowState.Added Or DataRowState.Deleted Or DataRowState.Modified)
               ComBulder1.DataAdapter = KindDa
               ComBulder2.DataAdapter = CodeDa
               ComBulder3.DataAdapter = InfoDa
               ComBulder4.DataAdapter = PostDa
               ComBulder5.DataAdapter = AttachDa

               If (Not (SaveDataset) Is Nothing) Then
                   KindDa.InsertCommand = ComBulder1.GetInsertCommand
                   KindDa.DeleteCommand = ComBulder1.GetDeleteCommand
                   KindDa.UpdateCommand = ComBulder1.GetUpdateCommand
                   '
                   CodeDa.InsertCommand = ComBulder2.GetInsertCommand
                   CodeDa.DeleteCommand = ComBulder2.GetDeleteCommand
                   CodeDa.UpdateCommand = ComBulder2.GetUpdateCommand
                   '
                   PostDa.InsertCommand = ComBulder4.GetInsertCommand
                   PostDa.DeleteCommand = ComBulder4.GetDeleteCommand
                   PostDa.UpdateCommand = ComBulder4.GetUpdateCommand
                   '
                   InfoDa.InsertCommand = ComBulder3.GetInsertCommand
                   InfoDa.DeleteCommand = ComBulder3.GetDeleteCommand
                   InfoDa.UpdateCommand = ComBulder3.GetUpdateCommand
                   '
                   AttachDa.InsertCommand = ComBulder5.GetInsertCommand
                   AttachDa.DeleteCommand = ComBulder5.GetDeleteCommand
                   AttachDa.UpdateCommand = ComBulder5.GetUpdateCommand

               End If

               KindDa.Update(SaveDataset, "Kind")
               CodeDa.Update(SaveDataset, "Coder")
               PostDa.Update(SaveDataset, "post")
               InfoDa.Update(SaveDataset, "Info")
               AttachDa.Update(SaveDataset, "Attach")

               MyDataset.Merge(SaveDataset, True, MissingSchemaAction.AddWithKey)

               MyDataset.AcceptChanges()
               MsgBox("تم الحفظ", MsgBoxStyle.Information + MsgBoxStyle.MsgBoxRight, "حفظ")

           End If


       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub

الشرح
  1. تعريف الحاوية المؤقته SaveDataset
  2. نسخ تخطيط الحاوية MyDataset الى الحاوية SaveDataset فقط نسخ تخطيط الجداول و العلاقات دون نسخ البيانات بمعنى اخر ستتواجد كل الجداول في الحاوية الجديدة مع العلاقات و القيود و التخطيط و كل شيئ باستثاء البيانات.
  3. الان نفحص وجود تغيرات في الحاوية MyDataset فاذا احتوت تغيرات جديدة منذ اخر استدعاء للطريقة (Acceptchanges) ? تابع شرحها بالاسفل
  4. اذا كان هناك تغيرات سنقوم باخذ نسخة من هذه التغيرات (الصفوف المضافة و المعدلة و المحذوفة) الى الحاوية SaveDataset.
  5. بعدها نقول له اذا كانت الحاوية SaveDataset ليست فارغة قم بمايلي:
  6. سنقوم بتحصيل جمل الادخال و التعديل و الحذف من الكائن CommandBilder بعد اسناده لناقل البيانات الخاص به DataAdapter ? سبق شرحه في الاعلى
  7.  KindDa.Update(SaveDataset, "Kind")  هذه الجملة و مابعدها ستقوم بتحديث القاعدة الاصلية (Access Database) كل جدول على حدا
  8. بعدها سنقوم بدمج التعديلات التي تمت بعد عملية تحديث القاعدة الاصلية وفق الطريقة Merge مع اضافة قيمة المفتاح الاساسي الراجع من القاعدة
  9. استدعاء الطريقة AcceptChanges و هي التي تعيد حالة MydataSet.HasChanges الى القيمة False بمعنى انها لا تحتوي على تغيرات جديدة يعد اخر عملية حفظ قمنا بها
يبدو انني نسيت ان اعيد حاوية جدول المواقع و هي وفق الكود التالي اذ اننا سنستخدمها في البرنامج
كود :
   Public Function LoadLoginDataSet() As DataSet
       LoadLoginTable()
       Return LoginDataSet
   End Function

و كذلك اجراء الحفظ الخاص به و هو كسابقه الخاص بحفظ التغيرات على الجداول السابقة

كود :
   Public Sub SaveLogins()
       Try
           Dim SaveLoginsDataSet As New DataSet
           SaveLoginsDataSet = LoginDataSet.Clone()

           If LoginDataSet.HasChanges = True Then
               SaveLoginsDataSet = LoginDataSet.GetChanges(DataRowState.Added Or DataRowState.Deleted Or DataRowState.Modified)
               '
               MsgBox("Hase new Ghange")
               ComBulder6.DataAdapter = LoginDa

               If (Not (SaveLoginsDataSet) Is Nothing) Then

                   LoginDa.InsertCommand = ComBulder6.GetInsertCommand
                   LoginDa.UpdateCommand = ComBulder6.GetUpdateCommand
                   LoginDa.DeleteCommand = ComBulder6.GetDeleteCommand
                   '

               End If
               LoginDa.Update(SaveLoginsDataSet, "LoginsTb")

               LoginDataSet.Merge(SaveLoginsDataSet, True, MissingSchemaAction.AddWithKey)

               LoginDataSet.AcceptChanges()
               MsgBox("تم الحفظ", MsgBoxStyle.Information + MsgBoxStyle.MsgBoxRight, "حفظ")


           End If

       Catch ex As Exception
           MsgBox(ex.ToString)


       End Try
   End Sub

نفس شرح الكود السابق ؟؟

هكذا نكون قد انتهينا من كلاس الاتصال و الحفظ الخاص بنا

يتبع......
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
الرد }}}
#3
الان ندخل الان الى الجانب العملي جانب التصميم و الربط مع النماذج
النموذج الاول لدينا هو نموذج ادخال الاكواد Form1 
هذا النموذج سيعالج الادخالات في جدولين جدول الاصناف Kind و جدول الاكواد Coder
حيث سيكون لدينا اصناف مثل الفجوال بيزك - السي شارب - الجافا - SQL - WPF و غيرها حسب ما تحب
و تحت كل صنف يمكنك ادخال الاكواد التي تريدها 
الفورم حسب التصميم الذي في الصورة اعلاه يحتوي على مجموعة من العناصر 

عناصر الربط مع الجدول Kind
  • ComboBox1 : ساستخدمه لعرض اسماء الاصناف المخزنة في الجدول Kind
  • KindTextBox : لاضافة اسم التصنيف
  • Not1TextBox:لاضافة ملاحظة على التصنيف
  • KindBindingSource:ساستخدمه هنا للربط مع الجدول Kind و استفيد من مزاياه الخاصة بالتنقل و الاضافة
  • BindingNavigator : ساستخدم قائمة تحتوي على ازرار الاضافة و الحذف و التعديل و كذلك التنقل و هي مرتبة بشكل جميل سنقوم بربطها بعنصر KindBindingSource مع تجاوز الطريقة الافتراضية لها في الحذف و الاضافة ساشرحها لاحقا
عناصر الربط مع جدول Coder
  • ComboBox2:ساستخدمه للوصول السريع الى عمل الكود او اسمه في الجدول Coder
  • Not1TextBox1:سنسجل فيه اسم الكود او عمله
  • Not2TextBox:وصف الكود المطلوب
  • Code2TextBox:تعقيب على الاجابة او شرح لعمل الكود
  • Code1TextBox:الاجابة او الكود و هو ليس مربع نص عادي TextBox بل هو مربع نص خاص يعرف بالاسم ColoredTextBox يحتوي على خصائص مميزة لعرض الكود بالالوان المطلوبة كما محرر الكود في لغة البرمجة و هو مكتبة خاصة مضمنة مع البرنامج عثرت عليه في ارجاء المنتدى على ما اعتقد و هو موجود على شبكة النت يمكنك من عرض النص وفق الفئة المختارة SQL-PHP-VB-#C-HTML
  • CoderBindingSource:للربط مع جدول Coder 
  • BindingNavigator1:سنربطها مع CoderBindingSource مع تجاوز طرقها كما سبق ذكره
هذه كل العناصر المطلوبة في النموذج الاول Form1

ناتي الان الى محرر الكود لنكتب اكوادنا الخاصة بكل العمليات اللازمة لاتمام المهمة


بداية ساقوم بتعريف هذه المتغيرات و ستعرف الحاجة منها مع كتابة الاكواد
كود :
   Dim A, B As Integer

حدث تحميل النموذج
كود :
   Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load

       Try
           '
           Me.KindBindingSource.DataSource = LoadDataSet()
           Me.KindBindingSource.DataMember = "Kind"
           '
           Me.CoderBindingSource.DataSource = KindBindingSource
           Me.CoderBindingSource.DataMember = "Kind_Coder"
           '
           BindingFileds()
           Code1TextBox.PreferredLineWidth = Code1TextBox.Width

       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try
   End Sub
الكود سهل على ما اعتقد و الشرح
  • ربط KindBindingSource بحاوية البيانات MyDataset عبر استدعاء الدالة loadDataSet التي سبق و انشأناها في الكلاس الخاص بالاتصال نربط مع الجدول Kind
  • الان نربط الكائن CoderBindingSource بالعلاقة المحضونة ضمنا في الكائن السابق KindBindingSource العلاقة Kind_Coder التي تؤمن الترابط بين الجدولين.
  • نستدعي الاجراء BindingFileds و هو اجراء خاص لربط العناصر بحقول قاعدة البيانات سيرد لاحقا.
  • السطر الاخير هو كود خاص لجعل امتداد سطر الكود المعروض بعرض مربع النص اثناء تحجيم البرنامج.
الاجراء الخاص بربط عناصر النموذج مع حقول قاعدة البيانات BindingFileds
كود :
   Private Sub BindingFileds()
       Try
           Me.KindTextBox.DataBindings.Add(New Binding("Text", KindBindingSource, "Kind"))
           Me.Not1TextBox.DataBindings.Add(New Binding("Text", KindBindingSource, "Not1"))
           '
           Me.Not1TextBox1.DataBindings.Add(New Binding("Text", CoderBindingSource, "Not1"))
           Me.Not2TextBox.DataBindings.Add(New Binding("Text", CoderBindingSource, "Not2"))
           Me.Code1TextBox.DataBindings.Add(New Binding("Text", CoderBindingSource, "Code1"))
           Me.Code2TextBox.DataBindings.Add(New Binding("Text", CoderBindingSource, "Code2"))

           '
           ComboBox1.DataSource = KindBindingSource
           ComboBox1.DisplayMember = "kind"
           ComboBox1.ValueMember = "Id"
           '
           ComboBox2.DataSource = CoderBindingSource
           ComboBox2.DisplayMember = "Not1"
           ComboBox2.ValueMember = "Id2"
           '
       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub

الكود سهل الفهم و هو مكرر مئات المرات في صفحات المنتدى

بعض الاكواد البسيطة تابع
كود :
   Private Sub CoderBindingSource_AddingNew(sender As Object, e As System.ComponentModel.AddingNewEventArgs) Handles CoderBindingSource.AddingNew
       Try
           Me.KindBindingSource.EndEdit()
       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try
   End Sub
و هو يستخدم عند اضافة كود جديد 
نستخدمه للحصول على رقم المفتاح الرئيسي من الجدول Kind حتى اذا اضفنا سجل جديد في الجدول Coder يتم تعبئة المفتاح الثانوي بشكل صحيح

زر الاضافة الخاص باضافة الاصناف
كود :
   Private Sub BindingNavigatorAddNewItem_Click(sender As System.Object, e As System.EventArgs) Handles BindingNavigatorAddNewItem.Click
       Try
           Me.KindTextBox.Focus()
       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub


زر الحذف العام (حذف التصنيف)
كود :
   'زر الحذف العام
   Private Sub BindingNavigatorDeleteItem_Click(sender As System.Object, e As System.EventArgs) Handles BindingNavigatorDeleteItem.Click
       Try
           If (Me.Validate() And Not (KindBindingSource Is Nothing)) Then

               Dim DeletStud As DialogResult = MessageBox.Show("سيتم حذف القسم الحالي", "انتبه", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.RightAlign)
               If DeletStud = Windows.Forms.DialogResult.Yes Then

                   KindBindingSource.EndEdit()
                   CoderBindingSource.EndEdit()
                   '
                   KindBindingSource.RemoveCurrent()
               End If

           End If

       Catch ex As Exception
           MessageBox.Show(ex.Message, "زر الحذف العام", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign)
       End Try

   End Sub

زر حذف كود
كود :
   Private Sub BindingNavigatorDeleteItem1_Click(sender As System.Object, e As System.EventArgs) Handles BindingNavigatorDeleteItem1.Click
       Try
           If (Me.Validate() And Not (CoderBindingSource Is Nothing)) Then

               Dim DeletStud As DialogResult = MessageBox.Show("سيتم حذف الكود الحالي", "انتبه", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.RightAlign)
               If DeletStud = Windows.Forms.DialogResult.Yes Then

                   CoderBindingSource.EndEdit()
                   '
                   CoderBindingSource.RemoveCurrent()
               End If

           End If

       Catch ex As Exception
           MessageBox.Show(ex.Message, "زر الحذف العام", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign)
       End Try

   End Sub

زر اضافة كود
كود :
   Private Sub BindingNavigatorAddNewItem1_Click(sender As Object, e As EventArgs) Handles BindingNavigatorAddNewItem1.Click
       CoderBindingSource.AddNew()
       Not1TextBox1.Focus()
   End Sub

اجراء خاص بصندوق النص ColoredTextBox
كود :
   Private Sub ComboBox2_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles ComboBox2.SelectedIndexChanged
       If ComboBox2.Items.Count > 0 And Code1TextBox.Text.Length > 0 Then
           Code1TextBox.GoHome()
       End If
     
   End Sub
وهو للذهاب الى السطر الاول من الكود المعروض في مربع النص عند تغير اسم الكود 

كود :
   Private Sub CoderBindingSource_CurrentChanged(sender As System.Object, e As System.EventArgs) Handles CoderBindingSource.CurrentChanged, CoderBindingSource.PositionChanged
       If ComboBox2.Items.Count > 0 And Code1TextBox.Text.Length > 0 Then
           Code1TextBox.GoHome()
       End If

   End Sub
End Class

نفس الكود السابق و لكن عند التنقل بين سجلات الاكواد عن طريق BindingNavigator

قمت ايضا باضافة مجموعة من الازار عند الضغط بزر الماوس الايمن فوق مربع نص الكود و هي مجموعة خدمية صغيرة يمكنك معرفة عملها وفق الكود التالي
كود :
#Region "ContextMenuStrip1"

   Private Sub Con_Copy_Click(sender As System.Object, e As System.EventArgs) Handles Con_Copy.Click
       Code1TextBox.Copy()
   End Sub

   Private Sub Con_Paste_Click(sender As System.Object, e As System.EventArgs) Handles Con_Paste.Click
       Code1TextBox.Paste()
   End Sub

   Private Sub Con_Clear_Click(sender As System.Object, e As System.EventArgs) Handles Con_Clear.Click
       Code1TextBox.Clear()
   End Sub


   Private Sub Con_Language_SelectedIndexChanged(sender As Object, e As System.EventArgs) Handles Con_Language.SelectedIndexChanged
       With Con_Language.Text
           Code1TextBox.SelectAll()
           Select Case Con_Language.Text
               Case Is = "VB"
                   Code1TextBox.Language = FastColoredTextBoxNS.Language.VB
               Case Is = "CSharp"
                   Code1TextBox.Language = FastColoredTextBoxNS.Language.CSharp
               Case Is = "HTML"
                   Code1TextBox.Language = FastColoredTextBoxNS.Language.HTML
               Case Is = "PHP"
                   Code1TextBox.Language = FastColoredTextBoxNS.Language.PHP
               Case Is = "SQL"
                   Code1TextBox.Language = FastColoredTextBoxNS.Language.SQL
               Case Else
                   Code1TextBox.Language = FastColoredTextBoxNS.Language.Custom
           End Select
           Code1TextBox.UpperLowerCase()

           Code1TextBox.GoHome()
       End With
   End Sub

   Private Sub Con_SelAll_Click(sender As System.Object, e As System.EventArgs) Handles Con_SelAll.Click
       Code1TextBox.SelectAll()
   End Sub


#End Region
كما ترى وضائف بسيطة نسخ و لصق و مسح و تغير لغة العرض في مربع النص

الان ناتي الى اهم كود وهو زر التخزين العام و هو كما يلي
كود :
   'زر التخزين العام
   Private Sub BtnSave_Click(sender As System.Object, e As System.EventArgs) Handles BtnSave.Click
       Try
           A = KindBindingSource.Position
           B = CoderBindingSource.Position
           '  
           saveCode()

           Me.Validate()
           '

           KindBindingSource.EndEdit()
           CoderBindingSource.EndEdit()
           '
           SaveData()

           '
           KindBindingSource.Position = A
           CoderBindingSource.Position = B

       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try
   End Sub
الشرح
  • في البداية نحتفظ بالموقع الحالي لكل من الاصناف و الكود
  • استدعي اجراء خاص SaveCode  ساشرح لما استخدمته
  • Me.Validate و ما بعدها سوف تتسبب في انهاء اي وضع تحرير للبيانات و بالتالي القيم المدخلة هي التي سيتم اعتمادها
  • SaveData هو اجراء الحفظ العام الخاص بنا و الذي قمنا بانشائه سابقا في كلاس الاتصال
  • بعد عملية الحفظ نعود الى مواقع السجلات التي خزناها سابقا
الاجراء SaveCode قمت باستخدامه بعدما لاحظت ان الاداة ColoredTextBox و لسبب ما لا تحدث قيمة النص المعروض بداخلها الى القاعدة كما يجري مع مربع النص العادي

الكود الخاص بالاجراء SaveCode
كود :
   Private Sub saveCode()
       If Not String.IsNullOrEmpty(Code1TextBox.Text) Then
           Dim RowCode As DataRowView
           RowCode = CoderBindingSource.Current
           RowCode("Code1") = Code1TextBox.Text
       End If
   End Sub
الكود بسيط وظيفته التقاط النص الى صف البيانات الحالي و تخزينه في المكان الموافق له (الحقل المطابق له في صف البيانات)

هذا كل ما لدينا للنموذج الاول Form1

يتبع....
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
الرد }}}
تم الشكر بواسطة: Sajad , abulayth , الوادي , Amir_Alzubidy , Hzar
#4
يا ابو ليلى،

ممتاز،

لكن تعديل لمعلومة بسيطة بالرغم أنني لم أدقق في كل الموضوع، ال SqlCleint يدعم CommandBuilder أيضاً.
الرد }}}
تم الشكر بواسطة: ابو ليلى , Amir_Alzubidy , Hzar
#5
كلامك صحصح اخي الوادي ساصحح المعلومة
تتوفر نسخة منه مع المزود SqlClient لكني لا افضل الحديث عنها الان لمحاذير ربما اذكرها لاحقا
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
الرد }}}
تم الشكر بواسطة: الوادي , Amir_Alzubidy , Amir_Alzubidy , Hzar
#6
الان ناتي الى النموذج الثاني Form2 و هو قلب برنامجنا الذي سيقوم بحفظ صفحات الموقع لدينا

ساعرض مجموعة من الصور هنا مع شرحها المرفق بالتمسيات للعناصر الموجودة عليها و سندخل لاحقا بالشرح
الصور مقسمة على مجموعات كما تتضح في النموذج اعلاه










بعد التوكل على الله نبدأ
سنقوم باستيراد بعض مجالات الاسماء للتعامل معها خلال الكود
كود :
Imports System.Data.OleDb
Imports System.Net
Imports System.IO
Imports System.Text.RegularExpressions
Imports System.Text
Imports System.Runtime
Imports System.Runtime.InteropServices

و بعض المتغيرات في بداية النموذج سنعرف الحاجة منها من خلال الشرح
كود :
Public Class Form2
   Dim A, B, C, D As Integer
   Dim sourceString As String
   Dim cookies As New CookieContainer()
   Dim Dt As New DataTable
   Dim PathStr As String
   Dim result As String = String.Empty

حدث تحميل النموذج
كود :
   Private Sub Form2_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
       Try

           Me.KindBindingSource.DataSource = LoadDataSet()
           Me.KindBindingSource.DataMember = "Kind"
           '
           Me.PostBindingSource.DataSource = KindBindingSource
           Me.PostBindingSource.DataMember = "Kind_post"
           '
           Me.InfoBindingSource.DataSource = PostBindingSource
           Me.InfoBindingSource.DataMember = "Kind_Info"
           '
           Me.AttachBindingSource.DataSource = InfoBindingSource
           Me.AttachBindingSource.DataMember = "Info_Attach"

           '
           BindingFileds()
           '
           CreaeDt()
           BindingNavigatorAddNewItem3.Enabled = False

       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub

تم شرحه سابقا عند التعامل مع النموذج Form1 مع زيادة طفيفة تتعلق بالجزئية CreaeDt 
و هو اجراء بسيط  لانشاء جدول سنحتاجه خلال العمل كما يلي
كود :
   ''' <summary>
   ''' اجراء بناء جدول خاص لتحميل المرفقات
   ''' </summary>
   ''' <remarks></remarks>
   Private Sub CreaeDt()
       Dt = New DataTable
       Dt.Clear()
       Dim Urlcol As New DataColumn("Urlcol", System.Type.GetType("System.String"))
       Dim Namecol As New DataColumn("Namecol", System.Type.GetType("System.String"))
       Dt.Columns.Add(Urlcol)
       Dt.Columns.Add(Namecol)
   End Sub

اجراء ربط الكائنات BindingFileds

كود :
   'ربط الكائنات
   Private Sub BindingFileds()
       Try
           Me.KindTextBox.DataBindings.Add(New Binding("Text", KindBindingSource, "Kind"))
           Me.Not1TextBox.DataBindings.Add(New Binding("Text", KindBindingSource, "Not1"))
           '
           Me.ponameTextBox.DataBindings.Add(New Binding("Text", PostBindingSource, "poname"))
           '
           Me.InfonameTextBox.DataBindings.Add(New Binding("Text", InfoBindingSource, "Infoname"))
           Me.UrlInfoTextBox.DataBindings.Add(New Binding("Text", InfoBindingSource, "UrlInfo"))

           '
           ComboBox1.DataSource = KindBindingSource
           ComboBox1.DisplayMember = "kind"
           ComboBox1.ValueMember = "Id"
           '
           ComboBox2.DataSource = PostBindingSource
           ComboBox2.DisplayMember = "poname"
           ComboBox2.ValueMember = "id_k"
           '
           ComboBox3.DataSource = InfoBindingSource
           ComboBox3.DisplayMember = "Infoname"
           ComboBox3.ValueMember = "IdInfo"
           '
           ListBox2.DataSource = AttachBindingSource
           ListBox2.DisplayMember = "AttachName"
           ListBox2.ValueMember = "AttachPath"


       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub


السيناريو المتبع في العمل سيكون كالتالي
بعد تحميل النموذج سنكون امام عمليات اضافة للاصناف و الفروع المشتقة منها و كذلك المقالات المشتقة من كل فرع 
وهي عملية روتينية ناقشناها في البند السابق عند التعامل مع Form1 
الجديد في الموضوع اننا سنكون امام صفحات HTML سنقوم بتخزينها في قاعدة البيانات من صفحة المستعرض مباشرة
و سنقوم ايضا بتخزين المرفقات المرتبطة بالمقال المعروض في المتصفح
طبعا التخزين ليس ضمن القاعدة بل في مجلد ضمن مسار البرنامج و اسمه AttachMents 
بينما سيتم تخزين اسم الملف و مساره فقط في جدول في القاعدة 
سيتم الدخول تلقائيا للموقع وفق اعدادات مسبقة انت تقوم بادخالها في نموذج خاص سنناقشه لاحقا
على اي حال لن اسهب كثيرا في الشرح هنا لانني ساقوم بالشرح مع كل خطوة تستلزم الشرح
ساضع الاكواد الخاصة بالادوات (الحذف و الحفظ و التعديل) بشكل عادي دون شرحها لاننا اصبحنا نعرف شرحها كما سبق

كود :
   'زر اضافة نوع
   Private Sub BindingNavigatorAddNewItem_Click(sender As System.Object, e As System.EventArgs) Handles BindingNavigatorAddNewItem.Click
       Try
           KindBindingSource.CancelEdit()
           KindBindingSource.AddNew()
           A = KindBindingSource.Position
           KindTextBox.Focus()
       Catch ex As OleDb.OleDbException
           MsgBox(ex.ToString)
       End Try
   End Sub

كود :
   'عند اضافة فرع
   Private Sub InfoBindingSource_AddingNew(sender As Object, e As System.ComponentModel.AddingNewEventArgs) Handles InfoBindingSource.AddingNew
       Try
           KindBindingSource.EndEdit()
       Catch ex As OleDb.OleDbException
           MsgBox(ex.ToString)
       End Try
   End Sub

كود :
   'زر اضافة فرع
   Private Sub BindingNavigatorAddNewItem1_Click(sender As System.Object, e As System.EventArgs) Handles BindingNavigatorAddNewItem1.Click
       Try
           PostBindingSource.CancelEdit()
           PostBindingSource.AddNew()
           B = PostBindingSource.Position
           ponameTextBox.Focus()
       Catch ex As OleDb.OleDbException
           MsgBox(ex.ToString)
       End Try
   End Sub

كود :
   'عند اضافة مقال
   Private Sub PostBindingSource_AddingNew(sender As Object, e As System.ComponentModel.AddingNewEventArgs) Handles PostBindingSource.AddingNew
       Try
           Me.KindBindingSource.EndEdit()
           ponameTextBox.Focus()
       Catch ex As OleDb.OleDbException
           MsgBox(ex.ToString)
       End Try
   End Sub



كود :
   'زر اضافة مقال
   Private Sub BindingNavigatorAddNewItem3_Click(sender As System.Object, e As System.EventArgs) Handles BindingNavigatorAddNewItem3.Click
       Try
           If sourceString = String.Empty Then
               MsgBox("لا يوجد مقالات محملة")
               Exit Sub
           End If
           InfoBindingSource.CancelEdit()
           InfoBindingSource.AddNew()

           InfonameTextBox.Text = WebBrowser1.DocumentTitle
           UrlInfoTextBox.Text = WebBrowser1.Url.AbsoluteUri
           '
           BindingNavigatorAddNewItem3.Enabled = False

           '===================
           Dim w1 As Integer = 0
           Using Con
               Dim sw1 As String = "Select Count(IdInfo) AS IdCount From Info Where UrlInfo Like '" & UrlInfoTextBox.Text & "'  "

               Dim MatchCommand As New OleDbCommand(sw1, Con)

               If Con.ConnectionString = Nothing Then Con.ConnectionString = ConnectionString
               Con.Open()
               '
               w1 = MatchCommand.ExecuteScalar
               '
           End Using
           '
           If w1 >= 1 Then
               MsgBox(" هذه المقالة موجودة و متوفرة في القاعدة لن يتم حفظها  ", MsgBoxStyle.Exclamation + MsgBoxStyle.MsgBoxRight + MsgBoxStyle.OkOnly, "تخزين المقال ")
               InfoBindingSource.CancelEdit()
               Exit Sub
           End If

           '==================
           C = InfoBindingSource.Position
       Catch ex As OleDb.OleDbException
           MsgBox(ex.ToString)
       End Try
   End Sub

هذا الكود يحتاج القليل من الشرح وهو كالتالي
عمليا عند اضافة مقال انا اقوم باضافته من المتصفح
لذلك ساختبر اذا كان المتصفح فعلا يحتوي على معلومات للصفحة المعروضة ؟ ساشرحه في الاسفل مع اجراء تحميل الصفحة
اذا كان المتصفح يحوي فعلا على معلومات ساقوم عندها باضافة اسم الموضوع و رابطه ايضا الى جدول المقالات
من خلال الصفحة المعروضة في المتصفح
عملية الاضافة لن تتم هكذا و الا اصبح لدي كم كبير من الصفحات المتشابهة
لذا جعلت عملية الاضافة تتم بعد التاكد ان الصفحة الحالية ليست مخزنه لدي في القاعدة وفق رابط الصفحة

سانتقل الان الى حدث اكتمال تحميل الصفحة في المستعرض لارتباطه بالكود السابق
عند اكتمال تحميل الصفحة انا قمت بوضع كود يقوم بنسخ محتويات الصفحة الى المتغير النصي sourceString
وهو مشمول في الاجراء التالي
كود :
   'اكتمال تحميل الصفحة
   Private Sub WebBrowser1_DocumentCompleted(ByVal sender As System.Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles WebBrowser1.DocumentCompleted
       Try
           sourceString = WebBrowser1.DocumentText
           '
           TxtUrl.Text = e.Url.ToString
           ToolStripStatusLabel2.Text = "    /    " & WebBrowser1.DocumentTitle
           Me.Text = WebBrowser1.DocumentTitle
           CollectAttachments(ListBox1)


           If sourceString = String.Empty Or sourceString.Length <= 14 Then
               BindingNavigatorAddNewItem3.Enabled = False
           Else
               BindingNavigatorAddNewItem3.Enabled = True
               Exit Sub
           End If


       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try
   End Sub

اعرف انني سادخل في متاهة شرح لاننا سنتفرع من اجراء الى اخر و كلها ترتبط ببعضها لذا وجب عليك ان تركز معي و ان تعذرني ان فاتني شرح جزئية معينة.
كما تلاحظ انا قمت بنسخ محتويات الصفحة الى المتغير sourceString 
مع بعض الاسطر التي تخص المستعرض مثل عرض اسم الموضوع الحالي في اسفل البرنامج  و اعلاه 
ثم اختبرت طول المتغير النصي لاقوم بتمكين عملية الاضافة من عدمها
للمعلومات ان طول النص الافتراضي للمستعرض هو 13 على ما اعتقد لانه يحتوي على Tag 
<\HTML><HTML> فارغ بدون محتويات و يبدأ بالتوسع مع وجود معلومات فعلية داخله
الكود ايضا يحتوي على دالة اخرى  CollectAttachments باختصار مهمتها جلب المرفقات عند اكتمال تحميل الصفحة ساشرحه عند وروده

نكمل باقي عمليات الاضافة


كود :
   'عند اضافة مرفق
   Private Sub AttachBindingSource_AddingNew(sender As Object, e As System.ComponentModel.AddingNewEventArgs) Handles AttachBindingSource.AddingNew
       Try
           InfoBindingSource.EndEdit()
       Catch ex As OleDb.OleDbException
           MsgBox(ex.ToString)
       End Try
   End Sub

اما عملية اضافة معلومات المرفقات الى جدول المرفقات في القاعدة فهي عملية متزامنه مع تحميل المرفق الى مجلد التخزين سناتي اليها لاحقا

عمليات الحذف سنؤجل الحديث عنها الان لانها عمليه طويله تجري باتجاهين القاعدة من جهة و الملفات المخزنة من جهة اخرى

نكمل مع باقي الاكواد 

كود :
   'تصفح
   Private Sub BtnBrowse_Click(sender As System.Object, e As System.EventArgs) Handles BtnBrowse.Click

       Try

           If Not Regex.IsMatch(TxtUrl.Text, "^((ht|f)tp(s?)\:\/\/|~/|/)?([\w]+:\w+@)?([a-zA-Z]{1}([\w\-]+\.)+([\w]{2,5}))(:[\d]{1,5})?((/?\w+/)+|/?)(\w+\.[\w]{3,4})?((\?\w+=\w+)?(&\w+=\w+)*)?") Then
               MessageBox.Show("موقع غير صحيح")
               Exit Sub
           Else
               SiteLogin(TxtUrl.Text.Trim)

           End If

       Catch ex As Exception
           Return
       End Try


   End Sub

الكود السابق للدخول الى صفحة المطلوبة وهو يختبر اولا ان الرابط المدخل هو تنسيق صحيح لروابط المواقع
ثم بعدها ينتقل الى دالة خاصة SiteLogin و هي لب العمل في البرنامج وهي تقوم بتسجيل الدخول الى الموقع ثم الانتقال الى الصفحة المطلوبة


كود :
   Private Sub SiteLogin(ByVal Url As String)
       'رابط الدخول من الاعدادت
       Dim LoginUrl As String = My.Settings.LoginUrl
       'حاوية الكوكيز
       Dim cookieContainer As New CookieContainer()
       'انشاء طلب للدخول
       Dim LoginRequest As HttpWebRequest = DirectCast(WebRequest.Create(LoginUrl), HttpWebRequest)
       LoginRequest.CookieContainer = New CookieContainer
       LoginRequest.ContentType = "application/x-www-form-urlencoded"
       LoginRequest.Method = "POST"
       LoginRequest.KeepAlive = True
       LoginRequest.AllowAutoRedirect = True
       LoginRequest.UserAgent = "Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9.0.1) Gecko/2008070208 Firefox/3.0.1"
       'البارمترات من الاعدادت
       Dim formParams As String = My.Settings.Parmms

       Dim bytes As Byte() = Encoding.UTF8.GetBytes(formParams)
       'كتابة البيانات
       LoginRequest.ContentLength = bytes.Length
       Using os As Stream = LoginRequest.GetRequestStream()
           os.Write(bytes, 0, bytes.Length)
       End Using
       'تحصيل الكوكيز من الموقع و تخزينه في الحاوية
       cookieContainer = GetUriCookieContainer(New Uri(LoginUrl))
       'جعل حاوية الطلب تحتضن الكوكيز
       LoginRequest.CookieContainer = cookieContainer
       'حاوية عامة للكوكيز على مستوى كل الطلبات
       cookies = New CookieContainer
       cookies = cookieContainer


       'استقبال الرد و تخزين الكوكيز
       Dim cookdisc As String
       Using httpWebResponse = DirectCast(LoginRequest.GetResponse(), HttpWebResponse)
           cookies.Add(httpWebResponse.Cookies)
           For Each cook As Cookie In httpWebResponse.Cookies
               result += cook.Name + "=" + cook.Value & ";"
               cookdisc = cook.Name + "=" + cook.Value & ";"

               InternetSetCookie(Url, cookdisc, cook.Expires)

           Next

       End Using
       WebBrowser1.Navigate(Url)

   End Sub

الشرح
  • متغير نصي يحمل رابط صفحة الدخول من الاعدادات
  • انشاء حاوية كوكيز تقوم باحتضان الكوكيز اثناء عملية الطلب و الرد
  • انشاء طلب مع اعطائه رابط صفحة الدخول
  • تفريغ حاوية الكوكيز الخاصة بالطلب
  • بعض المعلومات المطلوب ارسالها مع الطلب و هي تعلميات قياسية خاصة بصفحات الويب يمكنك ايجاد هذه المعلومات عند فتح مصدر اي صفحة ويب و هي كثيرة ليس المكان لشرحها
  • طريقة الطلب هي ادخال معلومات Post
  • المحافظة على الطلب حي يرزق مع تفعيل الارتداد و اعادة التوجيه وفق رد الملقم
  • معلومات قياسية اخرى تتعلق بالمتصفحات يمكنك الاستغناء عنها في بعض المواقع UserAgent
  • FormsParms متغير نصي يحمل معلومات الادخال الضرورية في الموقع و ناخذها من الاعدادات
  • مصفوفة من النوع Byte ستحمل بيانات الدخول وفق الترميز Utf8 الى الموقع
  • بدأ عملية كتابة بيانات المصفوفة في الموقع
  • GetUriCookieContainer هي دالة خاصة ستقوم بجلب الكوكيز من الموقع بعد استقبال رد المصادقة على الدخول و هي تستخدم مكاتب API .
  • ملئ حاوية الكوكيز الخاصة بالطلب بالكوكيز التي حصلنا عليها وفق الدالة السابقة و كذلك ملئ الحاوية العامة التي على مستوى البرنامج بالكوكيز اللازمة cookies
  • الاكواد اللاحقة يمكنك الاستغناء عنها اذ انني احببت ابقائها لتعرف طريقة الحصول على كل قيم الكوكيز و تستفيد منها كأن تخزنها او تعرضها؟
  • اخيرا التوجه الى الصفحة المطلوبة بعد ان تمت المصادقة على دخولنا
طبعا هناك سطر مسؤول عن توريث الكوكيز للمستعرض و هو السطر التالي
كود :
               InternetSetCookie(Url, cookdisc, cook.Expires)

كود :
   ''' <summary>
   ''' اجراء استخدمه عند الحاجة و هو للحصول على الكوكيز من الرابط
   ''' </summary>
   ''' <param name="uri">الرابط</param>
   ''' <returns>يعود بحاوية الكوكيز</returns>
   ''' <remarks>APi الدالة تستخدم مكاتب</remarks>
   Public Shared Function GetUriCookieContainer(uri As Uri) As CookieContainer
       Dim cookies As CookieContainer = Nothing
       Dim datasize As Integer = 8192 * 16
       Dim cookieData As New StringBuilder(datasize)
       '
       If Not InternetGetCookieEx(uri.ToString(), Nothing, cookieData, datasize, InternetCookieHttponly, IntPtr.Zero) Then
           If datasize < 0 Then
               Return Nothing
           End If

           cookieData = New StringBuilder(datasize)
           If Not InternetGetCookieEx(uri.ToString(), Nothing, cookieData, datasize, InternetCookieHttponly, IntPtr.Zero) Then
               Return Nothing
           End If
       End If
       If cookieData.Length > 0 Then
           cookies = New CookieContainer()
           cookies.SetCookies(uri, cookieData.ToString().Replace(";"c, ","c))
       End If
       Return cookies

الكود السابق يسيتخدم مكاتب API ساضعها هنا 
كود :
#Region "Get Set Cookies By APi"
   <DllImport("wininet.dll", CharSet:=CharSet.Auto, SetLastError:=True)>
   Private Shared Function InternetSetCookie(lpszUrlName As String, lpszCookieName As String, lpszCookieData As String) As Boolean
   End Function

   Private Const InternetCookieHttponly As Int32 = &H2000
   <DllImport("wininet.dll", CharSet:=CharSet.Auto, SetLastError:=True)> _
   Private Shared Function InternetGetCookieEx(pchURL As String, pchCookieName As String, pchCookieData As StringBuilder, ByRef pcchCookieData As UInteger, dwFlags As Integer, lpReserved As IntPtr) As Boolean
   End Function

#End Region

بعد دخولنا و عرض الصفحة اصبحنا الان امام صفحة معروضه في المتصفح
سنقوم الان بالتقاط المرفقات وفق الاجراء التالي
كود :
   ''' <summary>
   ''' اجراء تحصيل المرفقات من الصفحة و تجميعها في اللست بوكس
   ''' </summary>
   ''' <param name="list"></param>
   ''' <remarks></remarks>
   Private Sub CollectAttachments(ByVal list As ListBox)
       Try
           Dt.Rows.Clear()
           ProgressBar1.Value = 0
           If (WebBrowser1.Document IsNot Nothing) Then
               Dim Elems As HtmlElementCollection
               Dim WebOC As WebBrowser = WebBrowser1
               '
               '
               Elems = WebOC.Document.GetElementsByTagName("a")
               For Each elem As HtmlElement In Elems
                   Dim NameStr As String = elem.GetAttribute("href")

                   If ((NameStr IsNot Nothing) And (NameStr.Length <> 0)) Then

                       '(.zip/.rar/.pdf) This Only For CodeProject Now
                       If NameStr.ToLower().Contains("attachment.php?") Or
                           NameStr.ToLower().Contains(".zip") Or
                           NameStr.ToLower().Contains(".rar") Or
                           NameStr.ToLower().Contains(".doc") Or
                           NameStr.ToLower().Contains(".docx") Or
                           NameStr.ToLower().Contains(".pdf") Then

                           Dim siteUri As New Uri(NameStr)
                           Dim ContentStr As String = elem.InnerText
                           '===========
                           If siteUri.AbsoluteUri.LastIndexOf("/") And Not (NameStr.ToLower().Contains("attachment.php?")) Then
                               ContentStr = siteUri.AbsoluteUri.Substring(siteUri.AbsoluteUri.LastIndexOf("/") + 1)
                           End If

                           Dim row As DataRow = Dt.NewRow
                           row("Urlcol") = siteUri
                           row("Namecol") = ContentStr
                           Dt.Rows.Add(row)
                           '
                           list.DataSource = Dt
                           list.DisplayMember = "Namecol"
                           list.ValueMember = "Urlcol"

                       End If
                   End If
               Next
           End If

       Catch ex As WebException
           MsgBox(ex.ToString)
       End Try

   End Sub
و هو اجراء عادي يستخدم المكتبة RegularExpressions للبحث في مستند HTML عن العناصر التي تحتوي على المرفقات و من ثم الحصول على اسم المرفق ان امكن ؟؟؟؟ و كذلك الرابط
و بعدها ندخل اسم المرفق و رابطه في جدول خاص لنستخدمه لاحقا.
اسم المرفق؟؟؟؟ العملية كثيرا شاقة مع اختلاف بنية المواقع و كثرة استخدام السكربتات من كل شكل و لون و الكثير الكثير جعلني اعيد صياغة الكود عشرات المرات هنا و مازالت المفاجئات تتكرر  
بعد تعبئة الجدول سنقوم باضافة عناصره الى ListBox1 ليصبح لدينا شكل سهل و بسيط للتعامل مع الملفات و تحميلها فقط من خلال تحديدها من ListBox1 و من ثم زر Download .

ماذا بعد ذلك 
الان سندخل الى كود اضافة المرفقات في القاعدة و تحميل الملف و تخزينه في مجلد التخزين
يتبع.....  Sleepy
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
الرد }}}
تم الشكر بواسطة: الوادي , Amir_Alzubidy , Hzar
#7
السلام عليكم و رحمة الله و بركاته
كنا قد توقفنا عند الحصول على المرفقات و خزنا اسماء المرفقات و روابطها في جدول خاص ثم قمنا بعرض اسم المرفق
في ListBox1 تمهيدا لتحميلها حسب الرغبة
 نحن الان نمتلك رابط المرفق و اسمه , كما نملك ايضا حاوية الكوكيز و هي معبئة بالكوكيز لارسالها مع كل طلب دون ان نتعب
انفسنا بالحصول عليه مرة اخرى
كل ما تبقى هو انشاء طلب وفق رابط الملف و ارسال الكوكيز معه ثم استقبال رد الملقم و تخزين  طول الملف (حجمه) في متغير رقمي
و من ثم انشاء كائن MemoryStream للتعامل مع البيانات القادمة و بعدها كتابة هذه البيانات الى القرص الصلب و تخزينها بالاسم الذي لدينا
اقصد هنا اسم الملف المعروض في ListBox1
قبل ان ابدأ بعملية تخزين الملف ساقوم بالبحث عن الملف في مكانين
المكان الاول : هو مجلد التخزين فاذا توفر الملف فلن نحمله مرة اخرى.
المكان الثاني:قاعدة البيانات و تحديدا جدول المرفقات فكما تعلم نحن نضيف اسم الملف و مساره الى القاعدة مع كل عملية تحميل
البحث في جدول المرفقات سيتم وفق اسم الملف و رقم المقالة.
اي اننا سنبحث عن الملف المرتبط بالمقالة الحالية
كما اننا سنبحث في جدول المقالات ايضا عن المقالة الحالية المعروضة في المستعرض وفق رابط المقال
سنجري مجموعة من المقارنات لكي لا نحمل اسم مرفق لا يرتبط بالمقالة الحالية
اذ اننا سنحاول قدر الامكان تحميل المرفق المرتبط مع المقالة فقط 
بعد تحقق كل الشروط سنبدأ بتحميل الملف الى مجلد التخزين و اضافة رابط له في جدول المرفقات

في حدث زر التحميل DownloadAttachements_Click

كود :
   'زر تحميل المرفقات
   Private Sub DownloadAttachements_Click(sender As System.Object, e As System.EventArgs) Handles DownloadAttachements.Click
       Try

           If ListBox1.Items.Count > 0 Then

               'البحث عن الملف في مجلد التخزين
               Dim os As String() = System.IO.Directory.GetFiles(System.Windows.Forms.Application.StartupPath & "\AttachMents", ListBox1.Text)
               'البحث عن الملف في القاعدة
               Dim w1, w2 As Integer

               '
               Using Con

                   Dim rowinf As DataRowView
                   rowinf = InfoBindingSource.Current

                   Dim sw1 As String = "Select Count(AttachName) AS CountCn From Attaches Where  (AttachName Like '" & ListBox1.Text & "') And (Id_inf Like '" & rowinf("IdInfo") & "')  "
                   Dim sw2 As String = "Select Count(Infoname) As Cnt From Info Where UrlInfo Like '" & WebBrowser1.Url.AbsoluteUri & "'  "

                   Dim MatchCommand As New OleDbCommand(sw1, Con)
                   Dim SelCommand As New OleDbCommand(sw2, Con)

                   If Con.ConnectionString = Nothing Then Con.ConnectionString = ConnectionString
                   Con.Open()
                   '
                   w1 = MatchCommand.ExecuteScalar
                   w2 = SelCommand.ExecuteScalar
                   '
               End Using
               'عمليات فحص و مطابقة

               If w2 >= 1 And InfonameTextBox.Text <> WebBrowser1.DocumentTitle Then
                   Dim MsgResult As DialogResult = MessageBox.Show("المرفقات لا تتبع هذه المقالة , هناك مقالة لديك بهذا الاسم" & vbCrLf & "هل ما زلت تريد ربط المرفقات مع هذه  المقالة", "انتبه", MessageBoxButtons.OKCancel, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.RightAlign)
                   If MsgResult = Windows.Forms.DialogResult.Cancel Then Exit Sub
               ElseIf w2 < 1 Then
                   MessageBox.Show("لا يوجد مقالة لديك بهذا الاسم" & vbCrLf & "قم بخزن المقالة لديك قبل تحميل المرفقات", "انتبه", MessageBoxButtons.OK, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign)
                   Exit Sub
               End If
               '
               If w1 >= 1 Then
                   If os.Length >= 1 Then
                       MsgBox("المرفق المحدد موجود و مربوط مع المقال")
                       Exit Sub
                   Else
                       MsgBox("المسار متوفر في القاعدة بينماالمرفق غير متوفر في مجلد التخزين" & vbCrLf & "سيتم تحميل المرفق الى مجلد التخزين")
                       'هنا سنقوم بعملية تحديث تقتضي تحميل الملف فقط الى مجلد التخزين
                       If DownloadUrl(WebBrowser1.Url.AbsoluteUri) = False Then Exit Sub
                   End If
               Else
                   If os.Length >= 1 Then
                       MsgBox("الملف متوفر فقط في مجلد التخزين " & vbCrLf & "دون وجود رابط له في القاعدة" & vbCrLf & "سيتم اضافة رابط له في القاعدة")
                       'هنا سنقوم بحذف المرفق من المجلد لعدم وجود ترابط مع القاعدة
                       'Dim filePaths() As String = Directory.GetFiles(System.Windows.Forms.Application.StartupPath & "\AttachMents", ListBox1.Text)
                       'For Each filePath As String In filePaths
                       '    File.Delete(filePath)
                       'Next
                       Dim FILE_NAME As String = Application.StartupPath.ToString & "\AttachMents\" & ListBox1.Text

                       Me.Validate()
                       C = InfoBindingSource.Position
                       '
                       AttachBindingSource.AddNew()
                       '
                       D = AttachBindingSource.Position
                       '
                       Dim AttachRowview As DataRowView
                       AttachRowview = AttachBindingSource.Current
                       AttachRowview("AttachName") = ListBox1.Text
                       AttachRowview("AttachPath") = FILE_NAME
                       '
                       AttachBindingSource.EndEdit()
                       '
                       SaveData()
                       '
                       InfoBindingSource.Position = C
                       AttachBindingSource.Position = D

                   Else
                       'هنا نستخدم العملية كاملة لاضافة الملف الى القاعدة و مجلد التخزين
                       If DownloadUrl(WebBrowser1.Url.AbsoluteUri) = False Then Exit Sub
                       '
                       Me.Validate()
                       C = InfoBindingSource.Position
                       '
                       AttachBindingSource.AddNew()
                       '
                       D = AttachBindingSource.Position
                       '
                       Dim AttachRowview As DataRowView
                       AttachRowview = AttachBindingSource.Current
                       AttachRowview("AttachName") = ListBox1.Text
                       AttachRowview("AttachPath") = PathStr
                       '
                       AttachBindingSource.EndEdit()
                       '
                       SaveData()
                       '
                       InfoBindingSource.Position = C
                       AttachBindingSource.Position = D

                   End If


               End If
               '
           Else
               MsgBox("لا يوجد مرفقات او لم يتم الحصول على المرفق")
               Exit Sub
           End If

       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try


   End Sub

عمليات فحص و مطابقة تستخدم اكواد بسيطة الاغلب يعرفها 
جزء منها يهتم بالتعامل مع الملفات و الجزء الاخر جمل استعلام عادية للبحث في قاعدة البيانات
كنت افضل استخدام Linq To Dataset كون البيانات متوفرة لدينا في Dataset لكنني لم استخدم استعلامات Ling
منذ بداية الموضوع لذا سنبقى على جمل Sql .
الجزء المسؤول عن التحميل هو الدالة DownloadUrl 
وهي دالة عادية تلخص الحديث السابق المختص بارسال الطلب و استقبال الرد و هي كما يلي

كود :
   ''' <summary>
   ''' اجراء تحميل المرفقات
   ''' </summary>
   ''' <param name="Url">الرابط</param>
   ''' <returns></returns>
   ''' <remarks></remarks>
   Private Function DownloadUrl(ByVal Url As String) As Boolean

       Try
           Url = ListBox1.SelectedValue.ToString
           If Url.Contains("youtube") Then
               MsgBox("لا يمكن التحميل من هذا الموقع")
               Return False
               Exit Function

           End If

           Dim DownloadRequest As HttpWebRequest = DirectCast(WebRequest.Create(Url), HttpWebRequest)

           DownloadRequest.CookieContainer = New CookieContainer()
           DownloadRequest.CookieContainer = cookies
           DownloadRequest.KeepAlive = True
           '
           Dim DownloadResponse As WebResponse = DownloadRequest.GetResponse()
           '
           Dim intLen As Integer = CInt(DownloadResponse.ContentLength)

           ProgressBar1.Maximum = intLen
           Label1.Text = "0 / " & GetFileSize2(intLen)
           System.Windows.Forms.Application.DoEvents()
           '
           If intLen < 0 Then
               MsgBox("اما ان الملف مفقود او يوجد مشكلة في الاتصال")
               DownloadResponse.Close()
               Return False
               Exit Function
           End If
           '
           Dim memStream As MemoryStream
           Using stmResponse As IO.Stream = DownloadResponse.GetResponseStream()
               Dim buffer = New Byte(intLen) {}
               Dim bytesRead As Integer
               '
               Do
                   bytesRead += stmResponse.Read(buffer, bytesRead, intLen - bytesRead)
                   ProgressBar1.Value = bytesRead

                   Label1.Text = GetFileSize2(CInt(ProgressBar1.Value.ToString())) + " / " + GetFileSize2(intLen)

                   ProgressBar1.Refresh()
                   System.Windows.Forms.Application.DoEvents()

               Loop Until bytesRead = intLen

               memStream = New MemoryStream(buffer, False)
               '
               PathStr = System.Windows.Forms.Application.StartupPath & "\AttachMents\" & ListBox1.Text
               '
               My.Computer.FileSystem.WriteAllBytes(PathStr, buffer, False)
               '
               ProgressBar1.Value = 0
               Label1.Text = "0/0"
               DownloadResponse.Close()
               memStream.Close()
           End Using
           Return True
           '====================
           'هذه الطريقة تستخدم عندما يكون رابط الملف طبيعي اي لا يحتوي على اشاراة استفهام
           '    Dim FileName As String
           'If Url.EndsWith("/") Then
           '    Url = Url.Substring(0, Url.Length - 1)
           'End If
           'FileName = Url.Substring(Url.LastIndexOf("/"c) + 1)
           'MsgBox(FileName)
           ''  Exit Function
           'PathStr = System.Windows.Forms.Application.StartupPath & "\AttachMents\" & FileName
           ''========================
           'DownloadRequest.Abort()
           'DownloadResponse.Close()
           '
       Catch ex As WebException
           If WebExceptionStatus.Timeout = WebExceptionStatus.Timeout Then
               MsgBox("لا يوجد رد من الملقم قد يكون الملف مفقود")
               Return False
               Exit Function
           Else
               MsgBox(ex.ToString)
           End If
       End Try
       Return True

   End Function

ارجع للشرح في الاعلى لتعرف سيناريو العمل
تبقى لدينا عدة مشاكل ليس المكان لعدها فقط ما واجهني منها
بعض الروابط في الموقع لا تعمل اما ان الملفات مفقودة او ان رابط التحميل لا يشير صراحة الى الملف المطلوب
فمثلا يوجد بعض الملفات في الموقع و خصوصا ملفات الرار (rar) يشير رابطها الى موقع YouTube و يقودني الى فلم اطفال (صديقتي...؟؟)
على اي حال متى ما كان رابط التحميل صحيح و الملف موجود ستكون قادر على التحميل
يحصل احيانا ان الملقم لا يرسل لك طول الملف بشكل حقيقي و هذا يؤدي الى اجهاض عملية التحميل اذ ان معرفة طول الملف الحقيقي
اساسا غير مدعومة اثناء رد الملقم
بعد تحميل المرفق الى مجلد التخزين سيتم اضافة رابط له في جدول المرفقات في القاعدة كما قلت سابقا
هناك مشكلة بسيطة قد تحدث عند نقل البرنامج من كان الى مكان و هي ان مسار الملف المخزن في القاعدة سيكون غير صحيح
لذا اعتمدت طريقة اخرى لفتح الملف تعتمد على البحث عن الملف في مجلد التخزين ستراها لاحقا عند الحديث عنها
بعد ان حملت الملف و تم ربطه مع القاعدة سيتم عرض كل المرفقات المرتبطة مع المقالة المخزنة في عنصر ListBox2 تحت المقالة
و بامكانك النقر مرتين على اي عنصر داخلها ليتم فتح المرفق و فق المسا المخزن في القاعدة او عبر اسمه 
كود الحدث كما في الاسفل
كود :
   'فتح المرفقات من الجهاز
   Private Sub ListBox2_MouseDoubleClick(sender As Object, e As System.Windows.Forms.MouseEventArgs) Handles ListBox2.MouseDoubleClick
       Try
           If ListBox2.Items.Count > 0 Then
               'البحث عن الملف في مجلد التخزين
               Dim os As String() = System.IO.Directory.GetFiles(System.Windows.Forms.Application.StartupPath & "\AttachMents\", ListBox2.Text)


               If os.Length >= 1 Then
                   Dim filePath As String = String.Empty
                   For Each filePath In os
                       If filePath <> ListBox2.SelectedValue.ToString Then
                           MsgBox("المسار المحفوظ في القاعدة مختلف عن مسار الملف" & vbCrLf & "ربما تم تغير مسار مجلد التخزين")
                           'فتح الملف وفق مسار البحث و المطابقة
                           Process.Start(filePath)
                           Exit Sub
                       End If
                   Next

                   'فتح الملف وفق مسار القاعدة
                   Process.Start(ListBox2.SelectedValue.ToString)
               Else

                   'هنا سنقوم بحذف الادخال من القاعدة القاعدة
                   Dim DeleteFile As DialogResult = MessageBox.Show("رابط الملف متوفر فقط في القاعدة,دون وجود الملف في مجلد التخزين" & vbCrLf & "هل تريد حذف الادخال من القاعدة", "انتبه", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.RightAlign)
                   If DeleteFile = Windows.Forms.DialogResult.Yes Then

                       C = InfoBindingSource.Position
                       AttachBindingSource.RemoveCurrent()
                       SaveData()
                       InfoBindingSource.Position = C
                   End If

               End If

           End If

       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub

اذا دققت في الكود السابق ستجد فيه اسطر اضافية باختصار عملها
اذا لم نجد الملف متوفر في مجلد التخزين عندها سنقوم بحذف الارتباط الموجود له في القاعدة لكي لا يشير هذا السطر الى ملف غير موجود
كذلك انا قمت بعمل دالة بسيطة تقوم باعطاء الحجم لكل الملف وفق الطريقة القياسية (KB,MB,GB,TR) اذ ليس معقولا ان تقوم بعرض حجم الملف
كارقام بل كحجوم و هو افضل
في الحقية يوجد دالتين الاولى للملفات المخزنة لدينا في القرص
و الثانية للملفات التي نريد تحميلها
الدالة الاولى 
كود :
   'هذا من اجل الملفات المخزنة في مجلد التخزين
   Public Function GetFileSize(ByVal TheFile As String) As String
       If TheFile.Length = 0 Then Return ""
       If Not System.IO.File.Exists(TheFile) Then Return ""
       '---
       Dim TheSize As ULong = My.Computer.FileSystem.GetFileInfo(TheFile).Length
       Dim SizeType As String = ""
       '---

       Try
           Select Case TheSize
               Case Is >= 1099511627776
                   DoubleBytes = CDbl(TheSize / 1099511627776) 'TB
                   Return FormatNumber(DoubleBytes, 2) & " TB"
               Case 1073741824 To 1099511627775
                   DoubleBytes = CDbl(TheSize / 1073741824) 'GB
                   Return FormatNumber(DoubleBytes, 2) & " GB"
               Case 1048576 To 1073741823
                   DoubleBytes = CDbl(TheSize / 1048576) 'MB
                   Return FormatNumber(DoubleBytes, 2) & " MB"
               Case 1024 To 1048575
                   DoubleBytes = CDbl(TheSize / 1024) 'KB
                   Return FormatNumber(DoubleBytes, 2) & " KB"
               Case 0 To 1023
                   DoubleBytes = TheSize ' bytes
                   Return FormatNumber(DoubleBytes, 2) & " bytes"
               Case Else
                   Return ""
           End Select
       Catch
           Return ""
       End Try
   End Function

الدالة الثانية
كود :
   'هذا من اجل الملفات التي يتم تحميلها
   Public Function GetFileSize2(ByVal Flength As Integer) As String
       If Flength = 0 Then Return ""
       '---
       Dim TheSize As ULong = Flength
       Dim SizeType As String = ""
       '---

       Try
           Select Case TheSize
               Case Is >= 1099511627776
                   DoubleBytes = CDbl(TheSize / 1099511627776) 'TB
                   Return FormatNumber(DoubleBytes, 2) & " TB"
               Case 1073741824 To 1099511627775
                   DoubleBytes = CDbl(TheSize / 1073741824) 'GB
                   Return FormatNumber(DoubleBytes, 2) & " GB"
               Case 1048576 To 1073741823
                   DoubleBytes = CDbl(TheSize / 1048576) 'MB
                   Return FormatNumber(DoubleBytes, 2) & " MB"
               Case 1024 To 1048575
                   DoubleBytes = CDbl(TheSize / 1024) 'KB
                   Return FormatNumber(DoubleBytes, 2) & " KB"
               Case 0 To 1023
                   DoubleBytes = TheSize ' bytes
                   Return FormatNumber(DoubleBytes, 2) & " bytes"
               Case Else
                   Return ""
           End Select
       Catch
           Return ""
       End Try
   End Function


الدالتين متشابهتين فقط في الاولى يكون البارميتر المرسل هو مسار الملف بينما في الثانية يكون طول الملف هذا كل شيئ

وهذا في حدث تحديد الملف ليتم عرض الحجم وفق التحديد
كود :
   Private Sub ListBox2_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles ListBox2.SelectedIndexChanged
       Try
           If ListBox2.Items.Count > 0 Then
               Dim FilePath As String = System.Windows.Forms.Application.StartupPath & "\AttachMents\" & ListBox2.Text
               If Not IsNothing(FilePath) Then
                   Label3.Text = (GetFileSize(FilePath))
               End If
           Else
               Label3.Text = 0
           End If

       Catch ex As Exception

       End Try


   End Sub

طبعا انا وضعت Timer بسيط لتعطيل زر تحميل المرفقات عند عدم وجود ملفات للتحميل
كود :
   'تعطيل زر التحميل لعدم وجود مرفقات
   Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
       If ListBox1.Items.Count > 0 Then
           DownloadAttachements.Enabled = True
       Else
           DownloadAttachements.Enabled = False
       End If

   End Sub

الان و بعد ان فهمنا طبيعة العمل نعود الى الازرار القياسية و تحديدا زر حفظ المقال اي حفظ صفحة HTML داخل جدول المقالات
العملية مقسومة الى شقين الاول حفظ للحقول العادية في الجدول و الثاني حفظ لبنية HTML داخل الحقل Content
كما في السابق انا لن اخزن المقال مرتين في الجدول لذا ساقوم بالبحث عن اسم المقال بدليل رابط المقال فاذا وجد لدينا سنجهض عملية حفظ
محتوى الصفحة فقط و ليس كل اجراء الحفظ بمعنى اخر ربما لسبب ما انت تريد تسمية المقال باسم اخر غير الاسم الافتراضي لذا ستكون قادرا على ذلك بينما عملية تحديث محتويات الصفحة فلن تكون قادرا على ذلك اذ ان الصفحة محفوظة لديك في القاعدة


الشق الاول عملية الحفظ (حدث زر الحفظ العام) اذ ان الحفظ يتم على مستوى كل الجداول (فقط الاجزاء التي تحتوي على تحديثات) هي فقط من سيتم تحديثها

كود :
   'زر الحفظ
   Private Sub BtnSave_Click(sender As System.Object, e As System.EventArgs) Handles BtnSave.Click
       Try
           A = KindBindingSource.Position
           B = PostBindingSource.Position
           C = InfoBindingSource.Position
           '
           Me.Validate()
           '
           KindBindingSource.EndEdit()
           PostBindingSource.EndEdit()
           InfoBindingSource.EndEdit()
           '
           SaveData()
           InfoBindingSource.Position = C
           '
           SaveHtml(sourceString)
           sourceString = ""

           '
           KindBindingSource.Position = A
           PostBindingSource.Position = B
           BindingNavigatorAddNewItem3.Enabled = False
       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub

هل تذكر الاجراء SaveData في الكلاس Connect هو من سيقوم بعملية الحفظ
لاحظ وجود الاجراء SaveHtml و هو الشق الثاني من عملية الحفظ
كود :
   ''' <summary>
   ''' اجراء حفظ المقال
   ''' </summary>
   ''' <param name="HtmlText">"محتويات الصفحة"</param>
   ''' <remarks></remarks>
   Private Sub SaveHtml(ByVal HtmlText As String)
       Dim w2 As Integer

       Using Con
           Dim sw2 As String = "Select IdInfo  From Info Where UrlInfo Like '" & UrlInfoTextBox.Text & "'  "

           Dim SelCommand As New OleDbCommand(sw2, Con)

           If Con.ConnectionString = Nothing Then Con.ConnectionString = ConnectionString
           Con.Open()
           '
           w2 = SelCommand.ExecuteScalar
           '
       End Using
       '
       If w2 > 0 Then
           Dim UpdateText As String = "Update  Info Set Content = @Content Where IdInfo Like '" & w2 & "' "

           Try
               If UrlInfoTextBox.Text <> WebBrowser1.Url.AbsoluteUri Then
                   MsgBox(" الرابط الجديد مختلف عن الرابط المخزن ,قد تكون اخترت مقالة مختلفة  " & vbCrLf & "لن يتم تحديث محتويات المقالة", MsgBoxStyle.Exclamation + MsgBoxStyle.MsgBoxRight + MsgBoxStyle.OkOnly, "تخزين المقال ")
                   Exit Sub
               End If

               Using Con
                   If Con.ConnectionString = Nothing Then Con.ConnectionString = ConnectionString
                   If HtmlText <> "" And HtmlText.Length > 13 Then

                       Dim UpdateCommand1 As New OleDbCommand(UpdateText, Con)
                       If Con.State = ConnectionState.Open Then Con.Close()
                       Con.Open()
                       '
                       Dim CommandParameter1 As New OleDbParameter("@Content", OleDb.OleDbType.LongVarChar)
                       UpdateCommand1.Parameters.Add(CommandParameter1)
                       CommandParameter1.Value = HtmlText
                       Dim S As Integer = UpdateCommand1.ExecuteNonQuery
                       If S > 0 Then
                           ' MsgBox("نجحت عمليت تحديث المقالة")
                       Else
                           MsgBox("فشلت عملية التحديث")
                       End If
                   Else
                       MsgBox("لم يتم الحصول على محتويات الصفحة بعد")
                   End If
               End Using
           Catch ex As Exception
               MsgBox(ex.ToString)
           Finally
               Con.Close()
           End Try

       Else
           MsgBox("لم يتم حفظ عنوان المقال حاول حفظه ثانية")

       End If

   End Sub

اذا دققت في الكود السابق ككل ستجد انني اقوم اولا بتخزين حقول المقالة بدون ارسال محتويات الصفحة و بعدها انا اقوم بتخزين محتويات الصفحة بعد التاكد من من وجودها بدليل رابط المقال
طبعا اذا حاولت تخزين محتويات الصفحة الحالية المعروضة في المستعرض فانه سيقوم بعملية مطابقة رابط الصفحة في المتصفح مع الرابط المعروض حاليا في حقل المقالات فاذا وجد اختلاف سيعطيك رسالة مفادها ان المقالة الحالية التي تريد تخزينها او تحديث محتوياتها مختلفة عن المقالة المعروضة
هذه السلسلة من اجراءات الامان لكي لا نخزن محتويات صفحة لا تمت بصلة لعنوان المقالة
انتهينا من عمليات الحفظ
الان بعض الاجرائيات البسيط مثل عرض شريط حالة التحميل الخاص بالمستعرض كما يلي
كود :
   'حالة تحميل الصفحة
   Private Sub WebBrowser1_ProgressChanged(sender As Object, e As System.Windows.Forms.WebBrowserProgressChangedEventArgs) Handles WebBrowser1.ProgressChanged
       Try
           Dim CurProg As Double

           Dim MaxProg As Double

           CurProg = e.CurrentProgress

           MaxProg = e.MaximumProgress

           ToolStripProgressBar1.Value = (CurProg / MaxProg) * 100

       Catch ex As Exception
           '
       End Try

   End Sub

كود :
   'معلومات حالة التحميل
   Private Sub WebBrowser1_StatusTextChanged(sender As Object, e As System.EventArgs) Handles WebBrowser1.StatusTextChanged
       ToolStripStatusLabel1.Text = WebBrowser1.StatusText
   End Sub

اجراء الفلترة الخاص بزر الفلترة و البحث بحسب اسم المقال
كود :
   'فلترة
   Private Sub BtnSerch_Click(sender As System.Object, e As System.EventArgs) Handles BtnSerch.Click
       If TxtSerch.Text.Trim <> "" Then
           InfoBindingSource.Filter = "[Infoname] LIKE '%" & TxtSerch.Text & "%'"
       End If
   End Sub

زر مسح الفلتر
كود :
   'مسح الفلتر
   Private Sub ToolStripButton3_Click(sender As System.Object, e As System.EventArgs) Handles BtnRemoveFilter.Click
       InfoBindingSource.RemoveFilter()
   End Sub

زر الرجوع و الرئيسية و التحديث الخاصة بالمتصفح
كود :
   'رجوع
   Private Sub BtnBack_Click(sender As System.Object, e As System.EventArgs) Handles BtnBack.Click
       WebBrowser1.GoBack()
   End Sub

   'الرئيسية
   Private Sub BtnHome_Click(sender As System.Object, e As System.EventArgs) Handles BtnHome.Click
       WebBrowser1.GoHome()
   End Sub

   'تحديث
   Private Sub BtnRefresh_Click(sender As System.Object, e As System.EventArgs) Handles BtnRefresh.Click
       If Not WebBrowser1.Url.Equals("about:blank") Then
           WebBrowser1.Refresh()
       End If
   End Sub

صحيح هناك زر اضفته لاحقا للتراجع عن اضافة مقال
كود :
   'زر تراجع عن
   Private Sub BtnUndo_Click(sender As System.Object, e As System.EventArgs) Handles BtnUndo.Click
       InfoBindingSource.CancelEdit()
   End Sub

بعد ان قمنا بتخزين محتويات الصفحة في القاعدة اصبحنا قادرين الان على عرض المحتويات المخزنة في المستعرض
زر عرض المحتويات للمقالة الحالية
كود :
   ''' <summary>
   ''' تحميل الصفحة من القاعدة
   ''' </summary>
   ''' <param name="sender"></param>
   ''' <param name="e"></param>
   ''' <remarks></remarks>
   Private Sub BtnLoadContents_Click(sender As System.Object, e As System.EventArgs) Handles BtnLoadContents.Click
       Dim RowView As DataRowView
       RowView = InfoBindingSource.Current
       Dim Sel1 As String = "Select Content From Info Where IdInfo Like '" & RowView("IdInfo") & "' "
       Try
           Using Con
               If Con.ConnectionString = Nothing Then Con.ConnectionString = ConnectionString

               Dim Command1 As New OleDbCommand(Sel1, Con)
               If Con.State = ConnectionState.Open Then Con.Close()
               Con.Open()
               Dim Red1 As OleDbDataReader = Command1.ExecuteReader
               While Red1.Read
                   If Red1.HasRows = True And Not Red1.IsDBNull(0) Then
                       sourceString = Red1("Content")
                   Else
                       MsgBox("لا يوجد محتويات محفوظة لهذه المقالة")
                       Exit Sub
                   End If
               End While
               If sourceString <> "" Then
                   WebBrowser1.DocumentText = sourceString
               End If
           End Using

       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub

بقيت لدينا ازرار الحذف التي اجلت طرحها للاخر اذ ان عملية الحذف متزامنة بين القاعدة و الملفات المخزنة (المرفقات)
نبدا اولا مع حذف مقال مع مرفقاته
كود :
   'حذف مقال
   Private Sub BindingNavigatorDeleteItem3_Click(sender As System.Object, e As System.EventArgs) Handles BindingNavigatorDeleteItem3.Click
       Try
           If (Me.Validate() And Not (InfoBindingSource Is Nothing)) Then
               If InfoBindingSource.Count > 0 Then

                   Dim DeletStud As DialogResult = MessageBox.Show("سيتم حذف المقال الحالي", "انتبه", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.RightAlign)
                   If DeletStud = Windows.Forms.DialogResult.Yes Then


                       '==========حذف الملفات المرفقة=======================
                       'البحث عن الملف في مجلد التخزين
                       If ListBox2.Items.Count > 0 Then
                           For i As Integer = 0 To ListBox2.Items.Count - 1
                               Dim RowV As DataRowView = ListBox2.Items(i)
                               Dim os As String() = System.IO.Directory.GetFiles(System.Windows.Forms.Application.StartupPath & "\AttachMents", RowV("AttachName"))
                               If os.Length >= 1 Then
                                   Dim filePaths() As String = Directory.GetFiles(System.Windows.Forms.Application.StartupPath & "\AttachMents", RowV("AttachName"))
                                   For Each filePath As String In filePaths
                                       File.Delete(filePath)
                                   Next

                               End If
                               AttachBindingSource.RemoveAt(i)
                           Next
                       End If

                       'حذف المقال
                       InfoBindingSource.EndEdit()
                       InfoBindingSource.RemoveCurrent()
                   End If

               End If
           End If

       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub

و من ثم حذف فرع كامل مع كل مقالاته و الملفات المخزنه مع كل مقال
انا جعلت عملية الحذف محمية بكلمة مرور لكي لا نتورط و نحذف كل شيئ الا  بعد التأكد من ذلك
كود :
   'حذف فرع
   Private Sub BindingNavigatorDeleteItem1_Click_1(sender As System.Object, e As System.EventArgs) Handles BindingNavigatorDeleteItem1.Click
       Try
           If (Me.Validate() And Not (PostBindingSource Is Nothing)) Then

               If PostBindingSource.Count > 0 Then

                   Dim DeletStud1 As DialogResult = MessageBox.Show("سيتم حذف الفرع بما يحتويه من مقالات" & vbCrLf & "عملية الحذف محمية", "انتبه", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.RightAlign)
                   If DeletStud1 = Windows.Forms.DialogResult.Yes Then
                       Dim Message, Title, DefaultValue As String
                       Message = "ادخل كلمة المرور"
                       Title = "نموذج حماية"
                       DefaultValue = "ادخل كلمة المرور"

                       Dim ReturnValue As String = InputBox(Message, Title, DefaultValue)
                       If ReturnValue = "admin" Then

                           '====**********======
                           Dim DeletStud As DialogResult = MessageBox.Show("سيتم حذف الفرع بما يحتويه من مقالات", "انتبه", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.RightAlign)
                           If DeletStud = Windows.Forms.DialogResult.Yes Then

                               '==========حذف الملفات المرفقة=======================
                               'البحث عن الملف في مجلد التخزين
                               If InfoBindingSource.Count > 0 Then
                                   For p As Integer = 0 To InfoBindingSource.Count - 1
                                       '
                                       If AttachBindingSource.Count > 0 Then
                                           For i As Integer = 0 To AttachBindingSource.Count - 1
                                               Dim RowV As DataRowView = AttachBindingSource.Current
                                               Dim os As String() = System.IO.Directory.GetFiles(System.Windows.Forms.Application.StartupPath & "\AttachMents", RowV("AttachName"))
                                               If os.Length >= 1 Then
                                                   Dim filePaths() As String = Directory.GetFiles(System.Windows.Forms.Application.StartupPath & "\AttachMents", RowV("AttachName"))
                                                   For Each filePath As String In filePaths
                                                       File.Delete(filePath)
                                                   Next

                                               End If
                                               AttachBindingSource.RemoveAt(i)
                                           Next
                                       End If

                                       '==============


                                       ' InfoBindingSource.RemoveAt(p)
                                   Next


                               End If
                               '==========================
                               PostBindingSource.EndEdit()
                               InfoBindingSource.EndEdit()
                               '
                               PostBindingSource.RemoveCurrent()
                           End If



                       End If
                   Else
                       Exit Sub
                   End If
               End If

           End If

       Catch ex As Exception
           ' MsgBox(ex.ToString)
       End Try

   End Sub

حذف تصنيف باكمله مع كل الفروع و المقالات و المرفقات المرتبطه به كذلك محمي بكلمة مرور 
كود :
   'حذف التصنيف
   Private Sub BindingNavigatorDeleteItem_Click(sender As System.Object, e As System.EventArgs) Handles BindingNavigatorDeleteItem.Click
       Try
           If (Me.Validate() And Not (KindBindingSource Is Nothing)) Then
               If KindBindingSource.Count > 0 Then

                   Dim DeletStud1 As DialogResult = MessageBox.Show("سيتم حذف التصنيف الحالي بكل ما يحتويه" & vbCrLf & "عملية الحذف محمية", "انتبه", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.RightAlign)
                   If DeletStud1 = Windows.Forms.DialogResult.Yes Then
                       Dim Message, Title, DefaultValue As String
                       Message = "ادخل كلمة المرور"
                       Title = "نموذج حماية"
                       DefaultValue = "ادخل كلمة المرور"

                       Dim ReturnValue As String = InputBox(Message, Title, DefaultValue)
                       If ReturnValue = "admin" Then
                           '
                           Dim DeletStud As DialogResult = MessageBox.Show("سيتم حذف التصنيف الحالي بكل ما يحتويه", "انتبه", MessageBoxButtons.YesNo, MessageBoxIcon.Warning, MessageBoxDefaultButton.Button2, MessageBoxOptions.RightAlign)
                           If DeletStud = Windows.Forms.DialogResult.Yes Then
                               KindBindingSource.EndEdit()
                               PostBindingSource.EndEdit()
                               InfoBindingSource.EndEdit()
                               'حذف كل الفروع
                               For i As Integer = 0 To PostBindingSource.Count - 1
                                   DelAllPOsters()
                               Next
                               'حذف التصنيف
                               KindBindingSource.RemoveCurrent()

                           End If

                       End If

                   Else
                       Exit Sub

                   End If
               End If

           End If

       Catch ex As Exception
           MessageBox.Show(ex.Message, "زر الحذف العام", MessageBoxButtons.OK, MessageBoxIcon.Error, MessageBoxDefaultButton.Button1, MessageBoxOptions.RightAlign)
       End Try

   End Sub

انا استخدمت اجراء لحذف كل الفروع بداخل التصنيف DelAllPOsters
كود :
   'حذف فرع بشكل مباشر
   Private Sub DelAllPOsters()
       Try
           If (Me.Validate() And Not (PostBindingSource Is Nothing)) Then

               If PostBindingSource.Count > 0 Then

                   '==========حذف الملفات المرفقة=======================
                   'البحث عن الملف في مجلد التخزين
                   If InfoBindingSource.Count > 0 Then
                                   For p As Integer = 0 To InfoBindingSource.Count - 1
                                       '
                                       If AttachBindingSource.Count > 0 Then
                                           For i As Integer = 0 To AttachBindingSource.Count - 1
                                               Dim RowV As DataRowView = AttachBindingSource.Current
                                               Dim os As String() = System.IO.Directory.GetFiles(System.Windows.Forms.Application.StartupPath & "\AttachMents", RowV("AttachName"))
                                               If os.Length >= 1 Then
                                                   Dim filePaths() As String = Directory.GetFiles(System.Windows.Forms.Application.StartupPath & "\AttachMents", RowV("AttachName"))
                                                   For Each filePath As String In filePaths
                                                       File.Delete(filePath)
                                                   Next

                                               End If
                                               AttachBindingSource.RemoveAt(i)
                                           Next
                                       End If


                                   Next


                               End If
                               '==========================
                               PostBindingSource.EndEdit()
                               InfoBindingSource.EndEdit()
                               '
                               PostBindingSource.RemoveCurrent()
                           End If



                       End If

       Catch ex As Exception

       End Try

   End Sub
و هو يشبه اجراء حذف الفروع السابق لكنه بدون حماية

لم يتبقى لدينا شيئ في هذه الواجهة على ما اعتقد
اكتملت كل الخيوط و الكمال لله وحده
بقي لدينا نموذج الاعدادات الخاص بالدخول للمواقع و كيفية التعامل معه مع شرح بسيط عن مصادر الصفحات الخاصة بالمواقع ان امكنني ذلك

ساعرض بعض الصور الاولية لنموذج الاعدادات SettingForm مع اختلاف المواقع التي نريد الدخول اليها





اريدك فقط ان تركز في جزئية بارمترات الدخول لتعرف بعدها ماذا تعني كل هذه الحقول التي في النموذج
عمليا كل موقع لديه صفحة للدخول اليه و في هذه الصفحة يكون هناك مربعات نصوص لادخال اسم المستخدم و كلمة المرور 
وزر الدخول ايضا , ما نقوم به اثناء انشاء طلب و ارسال البارمترات معه هو عملية ادخال في هذه الحقول و من ثم ضغط زر الدخول
فاذا تمت المصادقة نكون قد حصلنا على مبتغانا
الازرار في اعلى النموذج هي اسماء الحقول في الموقع
اما مجموعة بيانات الدخول فهي المعلومات التي سندخلها 
اسم المستخدم الخاص بك و كلمة المرور ورابط صفحة الدخول للموقع مع اجراء الدخول
انا قمت بتزويد النموذج ببعض الاجراءات و اسماء الحقول الخاصة بالدخول لتجدها جاهزة
فمثلا موقعنا هنا يستخدم username لاسم المستخدم,password لكلمة المرور
و يعتمد الطريقة action=do_login
بينما في مواقع اخرى قد تختلف الطريقة وفق تصميم الموقع و اسماء الحقول
هذا النموذج مرتبط مع جدول LoginsTb في قاعدة البيانات حتى تكون قادرا على تخزين مواقعك و طريقة دخولك لها
و هو ايضا مرتبط باعدادات البرنامج حتى تحفظ اعدادتك للموقع الافتراضي الذي تريد الابحار في صفحاته
فقط اختر موقعك ثم (تخزين كاعداد افتراضي) و اترك الباقي على البرنامج فهو سيتكفل بارسال المعلومات من الاعدادت

اما في جانب الكود فليس هناك الكثير للتحدث عنه فهو كما سابق الاكواد التي شرحناها
كود :
Public Class SettingForm

   Dim C As Integer

حدث تحميل النموذج
كود :
   Private Sub SettingForm_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
       LoadLoginDataSet()

       Me.LoginBindingSource.DataSource = LoadLoginDataSet()
       Me.LoginBindingSource.DataMember = "LoginsTb"

       BindingFileds()

       TextBox1.Text = My.Settings.sitname

   End Sub

زر تخزين الاعدادت الافتراضية
كود :
   Private Sub BtnSaveSetting_Click(sender As System.Object, e As System.EventArgs) Handles BtnSaveSetting.Click
       Try
           My.Settings.LoginUrl = TxtLoginUrl.Text
           My.Settings.User = TxtUser.Text
           My.Settings.Password = TxtPassword.Text
           My.Settings.ActionStr = TxtAction.Text
           My.Settings.Parmms = TxtformParams.Text
           My.Settings.sitname = TxtSiteName.Text
           '
           My.Settings.Inputuser = Txus.Text
           My.Settings.Inputpass = Txps.Text
           My.Settings.InputAction = Txact.Text

           '
           My.Settings.Save()
           TextBox1.Text = My.Settings.sitname

       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub

زر تخزين لحفظ التعديلات و الاضافات الى الجدول LoginsTb

كود :
   Private Sub BtnSave_Click(sender As System.Object, e As System.EventArgs) Handles BtnSave.Click
       Try
           C = LoginBindingSource.Position
           '
           If TxtUser.TextLength > 0 And TxtPassword.MaxLength > 0 Then

               Dim usinput, passinput, actinput As String
               usinput = Txus.SelectedItem
               passinput = Txps.SelectedItem
               actinput = Txact.SelectedItem

               Dim formParams As String = String.Format(usinput & "={0}&" & passinput & "={1}&" & actinput & "={2}", TxtUser.Text, TxtPassword.Text, TxtAction.Text)
               TxtformParams.Text = formParams
           End If
           Me.Validate()
           LoginBindingSource.EndEdit()
           '
           SaveLogins()
           LoginBindingSource.Position = C
           '
       Catch ex As Exception
           MsgBox(ex.ToString)
       End Try

   End Sub

اجراء ربط الحقول 

كود :
   Private Sub BindingFileds()
       Me.TxtSiteName.DataBindings.Add(New Binding("Text", LoginBindingSource, "SiteName"))
       Me.TxtLoginUrl.DataBindings.Add(New Binding("Text", LoginBindingSource, "LoginUrl"))
       Me.TxtUser.DataBindings.Add(New Binding("Text", LoginBindingSource, "usernamee"))
       Me.TxtPassword.DataBindings.Add(New Binding("Text", LoginBindingSource, "Passworde"))
       Me.TxtAction.DataBindings.Add(New Binding("Text", LoginBindingSource, "ActionStr"))
       Me.TxtformParams.DataBindings.Add(New Binding("Text", LoginBindingSource, "formParams"))
       '
       Me.Txus.DataBindings.Add(New Binding("Text", LoginBindingSource, "Inputuser"))
       Me.Txps.DataBindings.Add(New Binding("Text", LoginBindingSource, "Inputpass"))
       Me.Txact.DataBindings.Add(New Binding("Text", LoginBindingSource, "InputAction"))


   End Sub

زر الاضافة

كود :
   Private Sub BindingNavigatorAddNewItem_Click(sender As System.Object, e As System.EventArgs) Handles BindingNavigatorAddNewItem.Click
       LoginBindingSource.AddNew()
       C = LoginBindingSource.Position
   End Sub

حدث تغير التحديد لتخزين نوع الاجراء في الحقل الهدف

كود :
   Private Sub ComboBox1_SelectedIndexChanged(sender As System.Object, e As System.EventArgs) Handles ComboBox1.SelectedIndexChanged
       If ComboBox1.SelectedItem <> String.Empty Then
           TxtAction.Text = ComboBox1.SelectedItem
       End If

   End Sub

تم بحمد الله و فضله , ارجو ان تعذروني عن كل خلل او تقصير حاصل ضمن المقال
و لاتنسونا من دعوة صالحة في ظهر الغيب في هذا الشهر الفضيل , اخوكم ابو ليلى

بالنسبة للبرنامج ساضعه لاحقا حتى تكتمل لدي بعض الافكار و يكون جاهزا للعمل دمتم بخير
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
الرد }}}
تم الشكر بواسطة: Amir_Alzubidy , الوادي , Hzar
#8
السلام عليكم
اخي ابو ليلى الذي منحك وسام العضو المميز 
الله يقدر له الخير اينما كان وجزاه الله خير 
ما شاء الله عليك يا ابو ليلى 
هذا شغل عظيم واسأل الله ان يعطيك اجر كل حرف كتبته و يجعله في ميزان اعمالك الصالحة 
الله يعطيك العافية والف الف الف شكرا جزيلا
الرد }}}
تم الشكر بواسطة: ابو ليلى , rnmr , rnmr , Hzar
#9
اشكرك اخي امير و اتمنى لك انت ايضا الاجر فيما تقدمه لهذا المنتدى فانت ايضا نبع من العطاء يستحق كل ثناء
و اشكر ايضا كل الاخوة الاعضاء الساهرين على حاجات اخوانهم لا تجد عندهم الفتور و الكسل يبغون اجرا في كل حرف يكتبوه
اعطاهم الله و كفاهم و جزاهم على نياتهم
و اشكر ايضا الحاضر الغائب الذي يسعى دائما لتقدم الموقع و المحافظة على تعب كل شخص فيه .
اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
الرد }}}
تم الشكر بواسطة: abulayth , Amir_Alzubidy , Hzar
#10
عرض لمعرفة اسماء الحقول و الاجراء في صفحة الدخول 


اللهم لك الحمد كما ينبغي لجلال وجهك و عظيم سلطانك
في حل و ترحال
الرد }}}
تم الشكر بواسطة: اباذر , Hzar , gharib , تعليموه , kebboud


المواضيع المحتمل أن تكون متشابهة .
الموضوع : الكاتب الردود : المشاهدات : آخر رد
  كيف تتعامل مع برنامج الإكسيل من برنامجك rinawi 7 6,626 12-11-22, 12:11 AM
آخر رد: خالد العصاوي
  نظرة على DropBox SDK و التعامل معها +برنامج رفع و تحميل ملفات ابو ليلى 4 4,871 08-09-22, 11:54 AM
آخر رد: saif2023
  برنامج مبيعات ومشتريات وإدارة أعمال ( الفاتورة الإلكترونية ) yassoo1985 2 2,245 04-06-22, 01:14 PM
آخر رد: yassoo1985
Heart طلب برنامج Advanced Installer أبو خالد الشكري 0 1,417 16-05-22, 09:12 PM
آخر رد: أبو خالد الشكري
  أهم طرق إدارة المخازن وتطبيقها على برنامج مخازن وارد ومنصرف Menna ahmeed 0 1,967 27-04-22, 12:52 PM
آخر رد: Menna ahmeed
  طريقة إنشاء برنامج طباعة ملصقات الباركود ملهمـ 1 4,397 22-12-21, 05:09 PM
آخر رد: alessam4pro
Heart [VB.NET] برنامج ادارة المطاعم و الكافيهات mgr21002100 6 6,650 14-01-21, 07:59 PM
آخر رد: abarrak
  مثال للتعامل مع الجداول المرتبطة - عن طريق الكلاسات ابو ليلى 25 15,191 04-10-20, 06:16 PM
آخر رد: محمد بن عطية
  لفهم كيفية الربط الذي يتم بين الجداول viv 4 4,991 03-10-20, 05:34 PM
آخر رد: Arfat007
  تفعيل برنامج Visual Studio 2019 Adilo idabdellah 4 11,512 20-05-20, 11:48 AM
آخر رد: الفاضي

التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم