Professional Documents
Culture Documents
Samer.selo@yahoo.com
Samerselo2005@hotmail.com
مالحظة هامة قبل البدء
حتى تستفٌد من المواضٌع فً هذا الكتٌب حول استخدام قواعد البٌانات مع تطبٌقات wpfبالشكل األمثل ٌجب أن ٌكون لدٌك معرفة ببرمجة
قواعد البٌانات وأساسٌات WPFو XAML
القسم األول – مدخل إلى قواعد البيانات
وأضف للمشروع قاعدة البٌانات المرفقة مع األمثلة وأنشئWpfDataEntery وسمهWPF Application أنشئ مشروعا جدٌدا من نوع
وذلك بالطرٌقة االعتٌادٌة عند إضافة مصدر بٌانات جدٌد وبذلك نكون قد أضفناCustomer باالعتماد على الجدولDataSet
xaml ثم عدل كودdocument outline ثم اختر األمرother Window ثمView ثم افتح قائمة. للمشروعCustomerDatSet
الخاص بالنافذة لٌصبح كما ٌلً كً نقوم بتقسٌم الشبكة إلى أربعة أقسام
<Window x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="294" Width="525">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="46*" />
<RowDefinition Height="216*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="138*" />
<ColumnDefinition Width="140*" />
</Grid.ColumnDefinitions>
</Grid>
</Window>
أنه أصبح بإمكانك سحب وإفالت التحكمات على النافذة تماما كماdocument outline ثم أضف أربعة أزرار للنافذة الحظ انه بعد تفعٌل
Revert وAdd وDelete لها إلىContent ثم غٌر خصائص األربعة أزرار لٌتم ضبط خاصٌةWindows Forms نفعل فً تطبٌقات
ثم أضف أربعة أزرار أخرى من أجل االنتقالbtnSave وbtnRevert وbtnAdd وbtnDelete إلىName و خاصٌةSave و
btnLast وbtnNext وbtnPrevious وbtnFirst ً كالتالname السابق والتالً واألول واألخٌر واجعل خاصٌة
وغٌر حجمهما لٌمأل كل واحد كامل مساحة قسم الشبكة الموجود فٌه ثم أضفGrid إلى القسمٌن السفلٌٌن من الـ2 عددstackpanel أضف
28 لصنادٌق النصوص إلىheight للٌمٌنً ثم اضبط خاصٌةTextBox الٌساري و أربعة تحكماتStackPanel لـlabel أربعة تحكمات
Auto إلىTextBox وLabel لجمٌع تحكماتWidth ثم اضبط خاصٌةLabel لمساواة ارتفاعها مع تحكمات
كما اضبطtxtCustomerID العلويTextBox لـname واجعل خاصٌةCustomerID العلوي إلىLabel لـContent اضبط قٌمة
وCity وFirst Name وLast Name إلىLable لبقٌة تحكماتContent ثم اضبط خاصٌةTrue له إلىIsReadOnly خاصٌة
txtCity وtxtFirstName وtxtLastName إلىTextBox لبقٌة تحكماتname خاصٌة
ً و أضف النص التالxaml انتقل إلى كودShow Data Sources ثم اخترData من أجل ربط صنادٌق النصوص بالبٌانات افتح قائمة
Text="{Binding ً كما ٌلCustomerID بالحقلtxtCustomerID لصندوق النصوصtext الذي ٌحدد كٌفٌة ربط الخاصٌة
ألنه للقراءة فقطOneWay وقمنا بتحدٌدPath=CustomerID, Mode=OneWay}
ألنه للقراءة والكتابةoneWay وقد أزلنا القٌمةText="{Binding Path=LastName} ً كما ٌلtxtLastName لـtext أضف الخاصٌة
لصنادٌق النصوص لدٌك مشابهاxaml كرر نفس العملٌة بالنسبة لصندوقً النصوص الباقٌٌن لربطها مع الحقول المناسبة وبذلك ٌصبح كود
ًللتال
Me.taCust.Fill(Me.CustomerData.Customer)
Me.DataContext = Me.CustomerData.Customer
للنافذةDataContext ثم ضبطنا قٌمة الخاصٌةFill الذي هو عبارة عن محول البٌانات بالبٌانات باستخدام الطرٌقةtaCust حٌث قمنا بملئ
فإن شغلت البرنامج هنا ستالحظ ظهور البٌانات على النافذةCustomer إلى الجدول
فً تطبٌقات النوافذBindingSource بدٌال عنWPF فً تطبٌقاتCollectionView عرف المتغٌر التالً على مستوى الفئة حٌث ٌعتبر
للنافذة بعد الكود الذي أدخلناه فٌها سابقاLoaded ومن أجل ربطه مع بٌاناتنا نستخدم الكود التالً فً الحدث
Me.View= CollectionViewSource.GetDefaultView(Me.CustomerData.Customer)
أجعل حدث النقر على أزرار التنقل كما فً الكود التالً من أجل تنفٌذ عملٌات التنقل بٌن السجالت
Me.View.MoveCurrentToFirst()
End Sub
Me.View.MoveCurrentToLast()
End Sub
للحصول على السطر الحالً ثم قمنا بعملٌة الحذفCtype حٌث تأكدنا أوال أننا لسنا خارج النطاق قبل عملٌة الحذف ثم استخدمنا الدالة
حٌث أنشانا سطرا جدٌدا وحددنا قٌمة افتراضٌة لحقل االسم األخٌر بما أنه ال ٌمكن أن ٌكون فارغا حسب قاعدة البٌانات ثم قمنا بإضافته
والسطر األخٌر من اجل إظهار السجل الجدٌدCustomer للجدول
If Me.CustomerData.HasChanges Then
Dim msg = "Are you sure that You want to loose all your changes?"
If MessageBox.Show(msg, Me.Title, MessageBoxButton.YesNo) = _
MessageBoxResult.Yes Then
Me.CustomerData.RejectChanges()
End If
End If
End Sub
إللغاءRejectChanges حٌث أظهرنا رسالة للمستخدم لٌؤكد أنه ٌرغب فعال بإلغاء جمٌع التعدٌالت التً قام بها وإن وافق نستخدم الطرٌقة
تلك التغٌٌرات
Me.taManager.CustomerTableAdapter = taCust
Try
If Me.CustomerData.HasChanges Then
If Me.taManager.UpdateAll(Me.CustomerData) > 0 Then
MsgBox("Saved")
End If
End If
Catch ex As Exception
)MsgBox(ex.ToString
End Try
End Sub
حٌث استخدمنا حلقة Tryاللتقاط أي خطأ ٌصدر عن قاعدة البٌانات وتأكدنا من أنه توجد تعدٌالت كً نقوم بحفظها وذلك باستخدام الدالة
HasChangesثم استخدمنا الطرٌقة UpdateAllمن أجل عملٌة الحفظ الفعلٌة
أنشئ مشروعا جدٌدا من النوع WPF Applicationوسمه ListBoxDataثم أضف قاعدة البٌانات المرفقة األمثلة إلى المشروع وفً معالج
إنشاء مجموعة البٌانات اختر الجدول Productsوسم مجموعة البٌانات ProductDataSetثم انتقل إلى محرر الكود الخاص بالنافذة
وأدخل فً الفئة الخاصة بالنافذة الكود التالً من أجل تحمٌل البٌانات
)Me.taProduct.Fill(Me.dsProduct.Product
End Sub
عد إلى محرر النافذة وأضف ListBoxإلى سطحها ثم عد إلى محرر الكود وأضف السطر التالً فً بعد السطر الموجود فً حدث Loaded
للنموذج حٌث نقوم بضبط قٌمة الخاصٌة ItemsSourc eلصندوق القائمة إلى الجدول Product
Me.ListBox1.ItemsSource=Me.dsProduct.Product
ونقوم بضبط قٌمة الخاصٌة DisplayMemberPathعلى nameمن أجل تحدٌد اسم العمود الذي نرٌد أن نظهر بٌاناته ولعمل ذلك أضف
السطر التالً بعد السطر السابق
"Me.ListBox1.DisplayMemberPath = "Name
ومن أجل ترتٌب البٌانات الظاهرة فً صندوق القائمة ٌمكننا استبدال قٌمة الخاصٌة ItemsSourceباستعالم لٌنك ولعمل ذلك استبدل السطر
Me.ListBox1.ItemsSource = Me.dsProduct.Product
بالسطر
انتقل إلى محرر النافذة وأضف صندوق نصوص أسفل صندوق القائمة حٌث سنستخدمه إلظهار وصف المنتج ولعمل ذلك سنحتاج لربط كال
التحكمٌن مع جدول البٌانات وأسهل طرٌقة فً WPFلربط عدة تحكمات هً ضبط ما ٌسمى بـ DataContextللنافذة بحٌث تستخدمها
التحكمات افتراضٌا
انتقل إلى محرر الكود واستبدل كافة الكود الخاص بالحدث Loadedللنافذة بالكود التالً
)Me.taProduct.Fill(Me.dsProduct.Product
Me.DataContext = From p In Me.dsProduct.Product Order By p.Name
عد إلى محرر xamlالخاص بالنافذة حٌث سنقوم بربط البٌانات من هناك حٌث سنقوم بتعدٌل الكود الخاص بصندوق القائمة لٌضبط قٌمة
الخاصٌتٌن ItemsSourceو DisplayMemberPathحٌث سٌصبح كود xamlالخاص بـ ListBoxكما ٌلً مع العلم أن الخاصٌة
IsSynchronizedWithCurrnetItemتتٌح مزامنة القٌمة المختارة فً صندوق القائمة مع السجل الحالً بحٌث تتٌح إظهار الوصف
المناسب للمنتج المختار فً صندوق النصوص
واستبدل كود صندوق النصوص بالكود التالً من أجل ربطه مع الحقل Description
ٌمكننا االستفادة أٌضا من مٌزة فً WPFهً إمكانٌة صنع قوالب للتحكمات Templatesولتجربة ذلك أزل صندوق النصوص من على
النافذة حٌث سنجعله ٌظهر داخل صندوق القائمة وسع اآلن صندوق القائمة لٌمأل النموذج ثم عدل كود xamlلصندوق القائمة لٌصبح كالتالً
حتى ٌمكننا إضافة التحكمات داخل صندوق القائمة الحظ حذف الخاصٌة DisplayMemberPath
></ListBox
داخل كود صندوق القائمة وقبل قسم إغالقها > </ListBoxأضف الكود التالً الذي ٌعرف قالب بٌانات DataTemplateداخل صندوق
القائمة ونضٌف بداخله StackPanelباتجاه أفقً كً ٌساعدنا فً ترتٌب التحكمات بداخل صندوق القائمة الحظ هنا أن جمٌع التحكمات فً
WPFهً مستوعبات ٌ Containersمكن وضع تحكمات بداخلها
><ListBox.ItemTemplate
><DataTemplate
>"<StackPanel Orientation="Horizontal
></StackPanel
></DataTemplate
></ListBox.ItemTemplate
ضع داخل الـ StackPanelتحكمان Labelبحٌث ٌكونان مربوطٌن مع العمودٌن nameو Descriptionكما ٌلً
شغل المشروع واختبره – الحظ ظهور عمودٌن للبٌانات بداخل صندوق القائمة وفً الحقٌقة بشكل عام ٌمكنك وضع أي تحكم بداخل صندوق
القائمة مثل األزرار أو صنادٌق النصوص أو مربعات االختٌار ...الخ
القسم الثالث – التعامل مع ComboBox
أنشئ مشروعا جدٌدا وسمه WpfLookup_VBثم أضف مصدر بٌانات جدٌد باستخدام المعالج واستخدم قاعدة البٌانات المرفقة مع األمثلة
واختر الجدول Ordersوسم الـ Datasetباالسم OrdersDataSetثم أضف مصدر بٌانات جدٌد واختر الجدول Customerبحٌث تحدد
الحقول CustomerIDو FirstNameو LastNameفقط وسم الـ DataSetباالسم CustomerLookupDataSet
افتح CustomerLookupDataSetثم انقر بزر الفأرة الٌمٌنً على CustomerTableAdapterثم اختر Configureوأضف قسم
Order Byلالستعالم الموجود فً الصفحة بحٌث ٌصبح االستعالم كما ٌلً
أغلق محرر مجموعة البٌانات ثم اذهب إلى قائمة Viewثم اختر إظهار نافذة Document Outlineالتً تساعدنا فً االنتقال عبر xaml
عدل كود Gridفً Xamlمن أجل تقسٌم الشبكة إلى أربعة أقسام بحٌث ٌصبح كما ٌلً
><Grid
><Grid.ColumnDefinitions
><ColumnDefinition Width="110*" /
><ColumnDefinition Width="168*" /
></Grid.ColumnDefinitions
><Grid.RowDefinitions
><RowDefinition Height="222*" /
><RowDefinition Height="40*" /
></Grid.RowDefinitions
></Grid
أدرج StackPanelفً كل قسم من القسمٌن العلوٌٌن للشبكة واجعل كل واحد منهما ٌمأل كامل مساحة قسم من أقسام الشبكة ثم أضف زرٌن
فً القسم الٌمٌنً السفلً للشبكة بحٌث تكون خاصٌة nameلهما btnSaveو btnAddو خاصٌة Contenetلهما Addو Saveثم
أضف أربعة تحكمات Labelفً الـ stackPanelالعلوي الٌمٌنً واضبط خاصٌة Widthلها إلى Autoثم اضبط خاصٌة Contentلها
بحٌث تكون من األعلى لألسفل Order IDو Customerو Order Dateو Ship Date
أدرج فً الـ StackPanelالعلوي الٌمٌنً تحكم TextBoxثم تحكم ComboBoxثم تحكمً TextBoxثم اضبط خاصٌة heightلهذه
التحكمات إلى 28كً نضبط ارتفاعها بشكل موازي الرتفاع تحكمات Labelفً القسم المقابل واضبط خاصٌة Widthلهذه التحكمات أٌضا
إلى Autoثم اختر الـ Gridواضبط الخاصٌة Marginإلى 6كما قم بضبط الخاصٌة Marginلجمٌع تحكمات Labelو textboxو
ComboBoxإلى 3
عدل كود xamlلصندوق النصوص األول كً ٌتم ربطه مع الحقل OrderIDفٌصبح كما ٌلً
ثم عدل كود xamlلصندوقً النصوص اآلخرٌن كً ٌتم ربطهما مع الحقلٌن OrderDateو ShipDateفٌصبح كما ٌلً
انتقل إلى محرر الكود الخاص بالنافذة وأضف المتغٌرات التالٌة العامة على مستوى النموذج كً نستخدمها للتعامل مع قواعد البٌانات
الخاص بالنافذة كً ٌتم ربط البٌانات مع النموذج وإظهارهاloaded أضف الكود التالً فً الحدث
Me.taOrder.Fill(Me.OrderData.Orders)
Me.taManager.OrdersTableAdapter = Me.taOrder
Me.DataContext = Me.OrderData.Orders
Me.ComboBox1.ItemsSource = Me.CustomerLookup
ً لٌتم إضافة معالج لحدث النقر على الزر ونقلك لمحرر الكود ثم أضف السطر التالAdd عد إلى محرر النافذة وانقر نقرا مزدوجا على الزر
مع المتغٌرات التً عرفناها فً القسم العام للفئة
Me.View= CollectionViewSource.GetDefaultView(Me.OrderData.Orders)
وأضف الكود التالً الذي ٌمثل كود إضافة سطر جدٌدAdd الخاص بالزرClick ثم انتقل لحدث
ًأنشئ معالج لحدث النقر على زر الحفظ وأدخل فٌه الكود التال
Try
If Me.OrderData.HasChanges Then
If Me.taManager.UpdateAll(Me.OrderData) > 0 Then
MsgBox("Saved")
End If
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
ً الذي سنقوم بتعدٌله حتى ٌقوم بإظهار حقلً االسم األخٌر واالسم األول فComboBox للنافذة واذهب إلى كودxaml انتقل إلى محرر
بدال عنها التً تمكننا من إضافةItemsTemplate حٌث سنضٌفDisplayMemberPath="LastName" البداٌة احذف الخاصٌة
ً لٌصبح كما ٌلComboBox التحكمات بداخله إلظهار االسم األخٌر واالسم األول عدل كود الـ
بترتٌب أفقً الذي سٌحتويStackPanel ثم أضفنا بداخلها تحكمDataTemplate وحددنا أنها من نوعitemTemplate حٌث أضفنا
و األخٌر معLastName داخله األول تم ربطه معTextBlock على تحكماتنا المضافة وٌتحكم بترتٌبها ثم أضفنا ثالثة تحكمات
بنفس الطرٌقة التً استخدمناها مع صنادٌق النصوصBinding والوسطً وضعنا فٌه فاصلة فقط وطرٌقة الربط هً باستخدامFirstName
سنرى فً هذا القسم كٌف ٌمكننا التحقق من البٌانات واستكشاف األخطاء فٌها حٌث توجد ثالث خطوات أساسٌة إلظهار رسائل التحقق
فً البداٌة ٌجب على الغرض Objectالذي ٌحمل البٌانات فً النموذج أن ٌحقق الواجهة IDataErrorInfoوإن كنت تستخدم DataSets
فهً تقوم بذلك من أجلك عندها ٌمكننا كتابة أكواد التحقق من البٌانات وإظهار رسائل األخطاء اعتمادا على حاجة المشروع الذي نقوم بتنفٌذه.
واألمر الثانً الذي ٌجب علٌنا عمله هو ضبط الـ Bindingالخاص بالتحكمات بأننا نرٌد إظهار إخبار مرئً عندما ٌفشل التحقق ونقوم بذلك
بضبط الخاصٌة ValidatesOnDataErrorsإلى Trueوفً الوضع االفتراضً ٌحٌط WPFالتحكم بإطار أحمر ولكنه ال ٌظهر أٌة رسالة
والمرحلة األخٌرة هً ضبط Validation.ErrorTemplateللتحكم كً نتمكن من إظهار الرسائل على التحكمات وجعلها تبدو تماما كما
نرٌد
أنشئ مشروعا جدٌدا من النوع WPF Applicationوسمه WPFDataValidationوٌتوجب علٌك استخدام قاعدة البٌانات المرفقة مع
األمثلة حٌث سنقوم بكتابة كود للتحقق من أن الحقل LastNameفً الجدول Customerغٌر فارغ قبل الحفظ
Customerوسمها من قائمة Dataاختر األمر Add New Data Sourceإلضافة DataSetللمشروع باختٌار الجدول
CustomerDataSetثم افتح CustomerDataSetوانقر بزر الفأرة الٌمٌنً على الجدول Customerثم اختر األمر View Code
لٌرٌنا Partial Class Codeوفً كود الفئة الجزئٌة CustomerDataTableأضف الدالة التالٌة للتحقق من أن LastNameغٌر فارغ
أضف إجراء معالجة الحدث Column Changedلـ CustomerDataTableمن أجل التحقق من قٌمة LastNameواجعل كوده ٌبدو
كما ٌلً
ثم أضف إجراء لمعالجة الحدث TableNewRowلـ CustomerDataTableوسٌكون كوده كما ٌلً
))Me.CheckLastName(CType(e.Row, CustomerRow
End Sub
عد إلى محرر تصمٌم نافذة المشروع كً نقوم بتصمٌم الواجهة وعدل كود xamlلدٌك كما فً الكود التالً الذي سٌشكل واجهة المشروع
حٌث تم تصمٌم الواجهة بنفس الطرٌقة التً اتبعناها سابقا فً األقسام السابقة
"<Window x:Class="Window1
"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid Margin="6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="95*" />
<ColumnDefinition Width="183*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="207*" />
<RowDefinition Height="55*" />
</Grid.RowDefinitions>
<StackPanel Name="StackPanel1">
<Label Height="28" Name="Label1" Width="Auto" Margin="3">
Last Name</Label>
<Label Height="28" Name="Label2" Width="Auto" Margin="3">
First Name</Label>
<Label Height="28" Name="Label3" Width="Auto"
Margin="3">Address</Label>
<Label Height="28" Name="Label4" Width="Auto"
Margin="3">City</Label>
<Label Height="28" Name="Label5" Width="Auto"
Margin="3">State</Label>
<Label Height="28" Name="Label6" Width="Auto" Margin="3">
Zip</Label>
</StackPanel>
<StackPanel Grid.Column="1" Name="StackPanel2">
<TextBox Height="28" Name="TextBox1" Width="Auto" Margin="3"
Text="{Binding Path=LastName}"/>
<TextBox Height="28" Name="TextBox2" Width="Auto" Margin="3"
Text="{Binding Path=FirstName}"/>
<TextBox Height="28" Name="TextBox3" Width="Auto" Margin="3"
Text="{Binding Path=Address}"/>
<TextBox Height="28" Name="TextBox4" Width="Auto" Margin="3"
Text="{Binding Path=City}" />
<TextBox Height="28" Name="TextBox5" Width="Auto" Margin="3"
Text="{Binding Path=State}"/>
<TextBox Height="28" Name="TextBox6" Width="Auto" Margin="3"
Text="{Binding Path=ZIP}"/>
</StackPanel>
<Button Grid.Column="1" Grid.Row="1" Margin="13,20,0,12"
Name="btnAdd" HorizontalAlignment="Left" Width="75">Add</Button>
<Button Grid.Column="1" Grid.Row="1" HorizontalAlignment="Right"
Margin="0,20,6,12" Name="btnSave" Width="75">Save</Button>
</Grid>
</Window>
و ضبطها إلى القٌمةValidatesOnDataErrors ً هBinding ومن أجل عملٌة التحقق من البٌانات ٌجب علٌنا إضافة خاصٌة إضافٌة لـ
السابق مثالxaml فً كودTextBox وذلك لجمٌع التحكماتTrue
انتقل إلى محرر الكود الخاص بالنافذة وأدخل الكود التالً الخاص بملئ البٌانات حٌث تمت كتابته بنفس األسلوب المتبع فً األقسام السابقة
Class Window1
Private CustomerData As New CustomerDataSet
Private taCust As New CustomerDataSetTableAdapters.CustomerTableAdapter
Private taManager As New CustomerDataSetTableAdapters.TableAdapterManager
Private View As CollectionView
Private Sub Window1_Loaded(ByVal sender As System.Object, _
ByVal e As System.Windows.RoutedEventArgs) Handles MyBase.Loaded
Me.taCust.Fill(Me.CustomerData.Customer)
Me.taManager.CustomerTableAdapter = taCust
Me.DataContext = Me.CustomerData.Customer
Me.View = _
CType(CollectionViewSource.GetDefaultView(Me.CustomerData.Customer), _
CollectionView)
End Sub
End Class
وانتقل للحقل الذي ٌلٌه ستالحظ أن صندوق النصوصLastName شغل المشروع وتأكد من رؤٌة البٌانات قم بمسح البٌانات من الحقل
الفارغ قد تمت إحاطته باللون األحمر داللة على فشل التحقق من البٌانات
ً وضع فٌه الكود التالAdd أضف إجراء معالجة النقر على الزر
ً وضع فٌه الكود التالSave أضف إجراء لمعالجة حدث النقر على الزر
Try
If Me.CustomerData.HasErrors Then
MsgBox("Please correct the errors first")
Else
If Me.CustomerData.HasChanges Then
If Me.taManager.UpdateAll(Me.CustomerData) > 0 Then
MsgBox("Saved.")
End If
End If
End If
Catch ex As Exception
MsgBox(ex.ToString)
End Try
ً كً نتحقق من عدم وجود أخطاء فCuastomerData العائدة لـHasErrors الحظ فً زري اإلضافة والحفظ أننا استخدمنا الطرٌقة
البٌانات قبل المتابعة
ValidationTemplate واجعل الكود فٌه ٌبدو كما ٌلً من أجل إنشاءApplication.xaml افتح الملف
<Application x:Class="Application"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
<Application.Resources>
<Style x:Key="myErrorTemplate" TargetType="Control">
<Setter Property="Validation.ErrorTemplate">
<Setter.Value>
<ControlTemplate>
<DockPanel LastChildFill="True">
<TextBlock DockPanel.Dock="Right"
Foreground="Red"
FontSize="14pt"
Margin="-15,0,0,0" FontWeight="Bold">*
</TextBlock>
<Border BorderBrush="Red" BorderThickness="1">
<AdornedElementPlaceholder Name="myControl"/>
</Border>
</DockPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<Trigger Property="Validation.HasError" Value="true">
<Setter Property="ToolTip"
Value="{Binding RelativeSource={x:Static RelativeSource.Self},
Path=(Validation.Errors)[0].ErrorContent}"/>
</Trigger>
</Style.Triggers>
</Style>
<Style TargetType="TextBox" BasedOn="{StaticResource myErrorTemplate}" />
<Style TargetType="CheckBox" BasedOn="{StaticResource myErrorTemplate}" />
<Style TargetType="ComboBox" BasedOn="{StaticResource myErrorTemplate}" />
</Application.Resources>
</Application>
هً خاصة بوقتControl Template من أجل تحدٌد أن هذه الـValidation.ErrorTemplate لـSetter حٌث ضبطنا الخاصٌة
على التحكم عند حدوث خطأToolTip ٌقوم بإظهارStyle.Triggers حدوث خطأ وقسم