تابع - الربط عنصرًا إلى عنصر Element To Element Binding
أبسط سيناريو يُمكن به إنجاز عملية الربط هو حينما يكون الكائن المَصدر أحد عناصر WPF, وتكون الخاصيّة المَصدر عبارة عن Dependency Property, وهذا لأن خصائص التبعيّة مبنيّة أساسًا على دعم التنبيه بالتغيّرات Change Notification كما ورد سابقًا, ولهذا عندما تُغيّر من قيمة الخاصية المَصدر في الكائن المَصدر فإن الخاصيّة الهدف في الكائن الهدف تتغيّر تلقائيًا, وهذا ماتريده بالضبط, ولا تحتاج لإتمام ذلك أيّة مُتطلبات إضافية!
وحتى تفهم كيف يُمكن ربط عنصر إلى آخر, لاحظ الصورة التالية التي تحتوي على عنصري تحكّم من عناصر WPF, شريط تمرير Silder, وأداة عرض النّص TextBlock, عندما تقوم بتحريك مُؤشِّر الشريط نحو اليمين يتزايد حجم النّص, وإذا قمت بتحريكه نحو الاتجاه المعاكس يتناقص حجم النّص. من الواضح أنه يُمكنك بسهولة إنجاز هذا السلوك من خلال الكود, من خلال مُعالجة الحدث Slider.ValueChanged ونسخ قيمة موضع المُؤشِّر الحالية وتعيين حجم الخط استنادًا إلى تلك القيمة, ولكن استخدام الربط عنصرًا إلى عنصر سيجعل ذلك أسهل!
قبل البدء, لست بحاجة لإجراء أيّة تعديلات على الكائن المَصدر (شريط التمرير), كلّ ما تحتاجه فقط هو ضبط مجال القِيم كما تفعل في العادة. الربط سيكون بداخل العنصر TextBlock, وبدل أن تقوم بإسناد قيمة نصية للخاصيّة FontSize ستستخدم تعبير الربط Binding Expression كما يلي:
تعابير الربط تستخدم امتدادات التمييز Markup Extensions (ولهذا تم إحاطتُها بـ {}) ,ويبتدأ تعبير الربط بالكلمة Binding لأنك هنا تقوم بإنشاء كائن من الفئة System.Windows.Data.Binding Class, ورغم ذلك يُمكنك تكوين كائن الربط هذا بعدّة طُرق, وفي مثل هذه الحالة نحتاج لإعداد خاصيّتين لهذا الكائن: الخاصيّة ElementName لتحديد اسم العنصر المَصدر, والخاصيّة Path لتحديد الخاصيّة المَصدر. لاحظ أن اسم الخاصيّة Path تم استخدامه هنا بدل الاسم Property لأن هذا المسار قد يكون إما اسم خاصيّة, وإما مُفهرِسًا Indexer, يُمكنك استخدام النقطة "." للفصل بين أسماء خصائص متداخلة مثل: Property1.Property2.Property3.
إنشاء الربط إجرائيًا
يُفضّل دائمًا عند إجراء عمليات الربط أن تستخدم XAML فهو أسهل وأكثر مرونة, ولكن ليس هناك ما يمنعك من إجراء الربط إجرائيًا من خلال الكود, وفي المثال التالي توضيح لكيفية إنشاء الربط المُستخدم في المثال السابق من خلال الكود:
يًمكنك كذلك إلغاء هذا الربط ومسحه إجرائيًا من خلال إجراءات الفئة BindingOperations, الإجراء ClearBinding والذي يأخذ وسيطة من النوع DependencyProperty الذي يحمل الربط الذي تحاول مسحه, بينما الإجراء ClearAllBindings يقوم بمسح كافة الارتباطات لعنصر ما.
كِلا الإجرائين السابقين يستدعيان الإجراء ClearValue الموجود في كل عنصر يرث الفئة DependencyObject بما فيها TextBlock, هذا الإجراء ببساطة يقوم بمسح القيمة المحليّة للخاصيّة (والذي هو في هذه الحالة تعبير الربط).
إن استخدام الربط من خلال XAML أكثر شيوعًا من الطريقة الإجرائية, لأنه أسهل وبتطلّب عملاً أقل, ولكن هناك حالتان خاصّتان قد تحتاج فيهما إلى استخدام الطريقة الإجرائية, الأولى عندما تحتاج إلى تكوين الربط بناءًا على شروط مُعيّنة, على سبيل المثال قد تحتاج إلى إجراء بعض عمليات التحقّق مثلاً من مُتغيّرات النظام قبل إنشاء الربط, وفي هذه الحالة يُمكنك تقليل حجم الكود بتعريف كائنات الربط مبدئيًا والاحتفاظ بها في موارد الإطار Window Resources من خلال XAML, وتكوين تلك الكائنات إجرائيًا بالشكل المطلوب كما سلف. وأما الحالة الثانيّة وهي عندما تريد مسح الربط والنخلّص منه, فلا يكفي ان تقوم بإسناد قيمة جديدة إلى الخاصية التي تريد مسحها بغرض التخلّص من الربط, فهذا لن يُؤثّر في الأمر شيئًا, بل ستحتاج لاستخدام الإجراء ClearBinding أو الإجراء ClearAllBindings كما سلف.
أوضاع الربط والتحديث Data Binding/Updating Modes
كما رأيت حتى الآن فإن مسار تغيّر الخصائص كان دائمًا من العنصر المَصدر إلى العنصر الهدف, ولكن من المُمكن بشكل ما أو بآخر أن تتغيّر قيمة الخاصية الهدف مُباشرةّ, ومن الجيّد في هذه الحالة أن ينعكس هذا التغيّر نحو العنصر المَصدر أيضًا, ففي المثال السابق قد تقوم من خلال الكود بتغيير قيمة الخاصية FontSize , عندها سستوقّع للحظة أن شريط التمرير سيقوم بتحديث نفسه تلقائيًا للقيمة ولكن هيهات! يُمكن حلّ هذه المسألة بساطة باستخدام الخاصية Mode للكائن Binding, حيث يُمكن التحكّم من خلالها في أوضاع مسار تغيّر البيانات, وهي كالتالي:
الصورة التالية تُلخّص الأوضاع السابقة:
عندما تتعامل مع الربط ثنائي الاتجاه TwoWay, أو أحادي الاتجاه نحو المَصدر OneWayToSource, فإنك قد ترغب أحيانًا في التحكّم في الكيفية التي يتمّ بها تحديث الهدف, على سبيل المثال, عتدما يقوم المستخدم بإدخال البيانات في عنصر TextBox, قد ترغب في أن يحدث التغيير فقط عندما يقوم المستخدم بالانتقال إلى عنصر التحكم التالي بواسطة المفتاح Tab, أو كلّما قام المستخدم بكتابة حرف أو تغيير حرف في عنصر TextBox, أو أن تتحكّم بنفسك من خلال الكود في الوقت الذي ترغب فيه بإجراء التحديث. الخاصية UpdateSourceTrigger من نوع الترقيم UpdateSourceTrigger Enum والموجودة في الفئة Binding تُتيح لك التحكم في تلك الكيفية من خلال أوضاع هي كالتالي:
كما يوجد هناك وضع افتراضي بالنسبة لعملية الربط فإن هناك أيصًا وضعًا افتراضيًا بالنسبة لعملية التحديث, على سبيل المثال, فالخاصيّة TextBox.Text افتراضيًا يكون وضع التحديث الخاص بها هو LostFocus .
خيارات الربط Data Binding Options
حتى الآن جميع الأمثلة السابقة تُركّز على الربط بين عنصرين من عناصر WPF, ولكن في أغلب الأحيان في التطبيقات التي تعتمد على قواعد البيانات Data-Driven Applications مصادر البيانات ليست عناصر WPF (ليست أدوات تحكّم واجهة الاستخدام), بل تكون كما ورد في مقدمّة هذا المقال – كائنات غير مرئية – وتحتاج لتمثيلها من خلال عناصر WPF المرئية, ويجب أن يكون متاحًا الوصول إلى خصائص تلك الكائنات , بحيث تكون تلك الخصائص عامّة Public. عند إجراء الربط مع كائنات ليست من عناصر WPF يجب عليك استبعاد استخدام الخاصية ElementName للفئة Binding, وإنما عليك استخدام أحد البدائل التالية:
الخاصيّة Source
يُمكنك التعامل مع الخاصيّة Source بشكل مُباشر, كلّ ما تحتاجه فقط هو أن يكون الكائن مَصدر البيانات جاهزًا للارتباط به, أبسط طريقة يُمكنك من خلالها استخدام هذه الخاصيّة هو أن تقوم بإسناد كائن ستاتيكي لها, قد يكون هذا الكائنن من كتابتك, او احد كائنات مكتبة Microsoft.NET, كما يُوضّح المثال التالي:
تعبير الرط في المثال السابق يُعيد كائنًا من النوع FontFamily من خلال الخاصيّة SystemFonts.IconFontFamily (لاحظ أنك تحتاج لاستخدام مُلحق الترمير s:Static), ثم بعد ذلك تمّ نحديد المسار Path نحو الخاصيّة FontFamily.Source (والتي تُمثّل اسم الخط), وستكون النتيجة هي ظهور الاسم Segoe UI في Windows Vista و Windows 7., يُمكن أيضًا استخدام الموارد الثابتة Static Resources , المثال التالي ستقوم بإنشاء مورد ثابت من النوع FontFamily والذي يُمثّل الخط Calibri:
وفيما يلي كيفية جعل TextBlock يستخدم هذا الكائن:
الخاصيّة RelativeSource
هناك طريقة أخرى لتحديد الكائن مَصدر البيانات, عبر الخاصيّة Binding.RelativeSource, والتي تُشير إلى ذلك الكائن حسب علاقته مع الكائن الهدف, هذه الخاصيّة من النوع RelativeSource, والذي هو في الأصل مُلحق ترميز (موروث من النوع MarkupExtension), وفيما يلي بعض الاستخدامات الشائعة لهذه الخاصيّة:
[INDENT]حيث desiredType هو نوع العنصر الأبوي (الكائن المَصدر).[/INDENT]
[INDENT]حيث desiredType هو نوع العنصر الأبوي (الكائن المَصدر).[/INDENT]
استخدام الخاصيّة RelativeSource مُفيد عند بناء قوالب الأدوات Control Templates , كما أن استخدام الخاصية Self مُفيد أيضًا في الكثير من الأحيان عندما تريد ربط خاصيّة لعنصر مع خاصيّة أخرى لنفس العنصر دون الحاجة لذكر اسم ذلك العنصر في تعبير الربط, المثال التالي سيُعطيك فكرة عن كيفية استخدامها, حيث سيتمّ ربط الخاصية ToolTip لعنصر TextBlock مع الخاصية Text لنفس العنصر, وبهذا سيتم عرض قيمة الخاصيّة Text ضمن ToolTip كلّما مررت فوق العنصر:
الخاصيّة DataContext
في بعض الأحيان, قد يكون لديك عدة عناصر WPF مرتبطة بنفس الكائن المَصدر, على سبيل المثال, افترض أن الكائن المصَدر سيكون كائنًا من النوع Person ويحتوي على الخصائص التالية: FName, LName, Age, وتريد أن تربط كل خاصيّة منها مع TextBox , وعليه سيكون لديك 3 عناصر TextBox ولتكن بداخل عنصر أبوي من نوع StackPanel, كما يُوضّح المثال التالي, في هذه الحالة قد تقوم بكتابة تعابير ربط طويلة نوعًا ما لكل عنصر TextBox لأنك ستقوم بتحديد الخاصية Source في تعابير الربط تلك, بالإضافة إلى المسار طبعًا:
من الجيّد في هذه الحالة أن تقوم بربط الخاصيةDataContext للعنصر StackPanel, والذي يحتوي على جميع عناصر TextBox (مع العلم أنه بالإمكان أيضًا ربط نفس الخاضية لعنصر أعلى من العنعصر StackPanel مثل Window نفسه, ولكن يُفضّل أن تختار العنصر الأقرب), ولربط الخاضيّة DataContext تحتاج أيضًا لاستخدام تعبير الربط, كما في المثال التالي:
والآن يُمكنك حذف الخاصيّة Source من تعابير الربط لعناصر TextBox الثلاثة, لأنه طالما لم يتم تحديد تلك الخاصيّة, فإن WPF سيقوم بفحص قيمة الخاصيّة DataContext لكل عنصر من عناصر TextBox, فإن كانت تلك القيمة Null سيقوم بفحص نفس الخاصيّة للعنصر الأعلى (StackPanel في هذه الحالة), وطالما أنها ليست Null ستصبج القيمة التي تحملها (myPerson) هي القيمة التي سيستخدمها WPF من أجل تعابير الربط لعناصر TextBox .
ملاحظة: إذا قمت باستخدام تعبير ربط مع تحديد الخاصيّة Source له بشكل صريح, فإن WPF سيستخدم قيمة تلك الخاصية حتى لو كانت الخاصيّة DataContext ليست Null .
أبسط سيناريو يُمكن به إنجاز عملية الربط هو حينما يكون الكائن المَصدر أحد عناصر WPF, وتكون الخاصيّة المَصدر عبارة عن Dependency Property, وهذا لأن خصائص التبعيّة مبنيّة أساسًا على دعم التنبيه بالتغيّرات Change Notification كما ورد سابقًا, ولهذا عندما تُغيّر من قيمة الخاصية المَصدر في الكائن المَصدر فإن الخاصيّة الهدف في الكائن الهدف تتغيّر تلقائيًا, وهذا ماتريده بالضبط, ولا تحتاج لإتمام ذلك أيّة مُتطلبات إضافية!
وحتى تفهم كيف يُمكن ربط عنصر إلى آخر, لاحظ الصورة التالية التي تحتوي على عنصري تحكّم من عناصر WPF, شريط تمرير Silder, وأداة عرض النّص TextBlock, عندما تقوم بتحريك مُؤشِّر الشريط نحو اليمين يتزايد حجم النّص, وإذا قمت بتحريكه نحو الاتجاه المعاكس يتناقص حجم النّص. من الواضح أنه يُمكنك بسهولة إنجاز هذا السلوك من خلال الكود, من خلال مُعالجة الحدث Slider.ValueChanged ونسخ قيمة موضع المُؤشِّر الحالية وتعيين حجم الخط استنادًا إلى تلك القيمة, ولكن استخدام الربط عنصرًا إلى عنصر سيجعل ذلك أسهل!
قبل البدء, لست بحاجة لإجراء أيّة تعديلات على الكائن المَصدر (شريط التمرير), كلّ ما تحتاجه فقط هو ضبط مجال القِيم كما تفعل في العادة. الربط سيكون بداخل العنصر TextBlock, وبدل أن تقوم بإسناد قيمة نصية للخاصيّة FontSize ستستخدم تعبير الربط Binding Expression كما يلي:
PHP كود :
<StackPanel> <Slider Name="sliderFontSize" Margin="3" Minimum="1" Maximum="32" Value="12" TickFrequency="1" TickPlacement="TopLeft"> </Slider> <TextBlock Margin="10" Text="Simple Text" Name="lblSampleText" FontSize="{Binding ElementName=sliderFontSize, Path=Value}"> </TextBlock> </StackPanel>
تعابير الربط تستخدم امتدادات التمييز Markup Extensions (ولهذا تم إحاطتُها بـ {}) ,ويبتدأ تعبير الربط بالكلمة Binding لأنك هنا تقوم بإنشاء كائن من الفئة System.Windows.Data.Binding Class, ورغم ذلك يُمكنك تكوين كائن الربط هذا بعدّة طُرق, وفي مثل هذه الحالة نحتاج لإعداد خاصيّتين لهذا الكائن: الخاصيّة ElementName لتحديد اسم العنصر المَصدر, والخاصيّة Path لتحديد الخاصيّة المَصدر. لاحظ أن اسم الخاصيّة Path تم استخدامه هنا بدل الاسم Property لأن هذا المسار قد يكون إما اسم خاصيّة, وإما مُفهرِسًا Indexer, يُمكنك استخدام النقطة "." للفصل بين أسماء خصائص متداخلة مثل: Property1.Property2.Property3.
إنشاء الربط إجرائيًا
يُفضّل دائمًا عند إجراء عمليات الربط أن تستخدم XAML فهو أسهل وأكثر مرونة, ولكن ليس هناك ما يمنعك من إجراء الربط إجرائيًا من خلال الكود, وفي المثال التالي توضيح لكيفية إنشاء الربط المُستخدم في المثال السابق من خلال الكود:
PHP كود :
Binding binding = new Binding() { ElementName = "sliderFontSize", Path = new PropertyPath("Value"),}; lblSampleText.SetBinding(TextBlock.FontSizeProperty, binding);
يًمكنك كذلك إلغاء هذا الربط ومسحه إجرائيًا من خلال إجراءات الفئة BindingOperations, الإجراء ClearBinding والذي يأخذ وسيطة من النوع DependencyProperty الذي يحمل الربط الذي تحاول مسحه, بينما الإجراء ClearAllBindings يقوم بمسح كافة الارتباطات لعنصر ما.
PHP كود :
BindingOperations.ClearAllBindings(lblSampleText);
إن استخدام الربط من خلال XAML أكثر شيوعًا من الطريقة الإجرائية, لأنه أسهل وبتطلّب عملاً أقل, ولكن هناك حالتان خاصّتان قد تحتاج فيهما إلى استخدام الطريقة الإجرائية, الأولى عندما تحتاج إلى تكوين الربط بناءًا على شروط مُعيّنة, على سبيل المثال قد تحتاج إلى إجراء بعض عمليات التحقّق مثلاً من مُتغيّرات النظام قبل إنشاء الربط, وفي هذه الحالة يُمكنك تقليل حجم الكود بتعريف كائنات الربط مبدئيًا والاحتفاظ بها في موارد الإطار Window Resources من خلال XAML, وتكوين تلك الكائنات إجرائيًا بالشكل المطلوب كما سلف. وأما الحالة الثانيّة وهي عندما تريد مسح الربط والنخلّص منه, فلا يكفي ان تقوم بإسناد قيمة جديدة إلى الخاصية التي تريد مسحها بغرض التخلّص من الربط, فهذا لن يُؤثّر في الأمر شيئًا, بل ستحتاج لاستخدام الإجراء ClearBinding أو الإجراء ClearAllBindings كما سلف.
أوضاع الربط والتحديث Data Binding/Updating Modes
كما رأيت حتى الآن فإن مسار تغيّر الخصائص كان دائمًا من العنصر المَصدر إلى العنصر الهدف, ولكن من المُمكن بشكل ما أو بآخر أن تتغيّر قيمة الخاصية الهدف مُباشرةّ, ومن الجيّد في هذه الحالة أن ينعكس هذا التغيّر نحو العنصر المَصدر أيضًا, ففي المثال السابق قد تقوم من خلال الكود بتغيير قيمة الخاصية FontSize , عندها سستوقّع للحظة أن شريط التمرير سيقوم بتحديث نفسه تلقائيًا للقيمة ولكن هيهات! يُمكن حلّ هذه المسألة بساطة باستخدام الخاصية Mode للكائن Binding, حيث يُمكن التحكّم من خلالها في أوضاع مسار تغيّر البيانات, وهي كالتالي:
- الوضع أُحادي الاتجاه OneWay: يتمّ تحديث قيمة الخاصيّة الهدف عندما تتغيّر قيمة الخاصيّة المَصدر.
- الوضع ثنائي الاتجاه TwoWay: يتمّ تحديث قيمة الخاصيّة المَصدر أو الهدف بتغيّر قيمة الخاصيّة الأخرى, هذا الوضع يُستخدم عادة عند التعامل مع عناصر التحكّم التي يُسمح فيها للمستخدم بالتعديل عليها, مثل DataGrid, TextBox, حيث تنتقل التغيّرات من هذه العناصر مباشرةً إلى الكائن المَصدر المرتبط بها.
- الوضع أُحادي الاتجاه نحو المَصدر OneWayToSource: هذا الوضع مُعاكس للوضع الأول OneWay. حيث يتمّ تحديث قيمة الخاصيّة المَصدر كُلّما تمّ تحديث الخاصيّة الهدف. هذا الوضع مُفيد جدًا خصوصًا في الحالة التي تكون فيها الخاصيّة المَصدر ليست خاصيّة تبعيّة .
- الوضع لأول مرّة فقط OneTime: هذا الوضع مُماثل للوضع الأول OneWay باستثناء أن أيّ تغيّر يتمّ لاحقًا على الخاصيّة المَصدر لايتمّ أخذه بالحسبان ولا تتأثّر به الخاصيّة الهدف.
- الوضع الافتراضي Default: هذا الوضع يعتمد على الخاصيّة الهدف, يُمكن أن يكون هذا الوضع قي هذه الحالة إما ثنائي الاتجاه TwoWay (بالنسبة للخصائص الهدف القابلة للكتابة Writable Properties), أو أحادي الاتجاه, جميع الخصائص تعتمد على هذا الأسلوب, إلا إذا قمت باختيار وضع مُغاير بشكل صريح.
الصورة التالية تُلخّص الأوضاع السابقة:
عندما تتعامل مع الربط ثنائي الاتجاه TwoWay, أو أحادي الاتجاه نحو المَصدر OneWayToSource, فإنك قد ترغب أحيانًا في التحكّم في الكيفية التي يتمّ بها تحديث الهدف, على سبيل المثال, عتدما يقوم المستخدم بإدخال البيانات في عنصر TextBox, قد ترغب في أن يحدث التغيير فقط عندما يقوم المستخدم بالانتقال إلى عنصر التحكم التالي بواسطة المفتاح Tab, أو كلّما قام المستخدم بكتابة حرف أو تغيير حرف في عنصر TextBox, أو أن تتحكّم بنفسك من خلال الكود في الوقت الذي ترغب فيه بإجراء التحديث. الخاصية UpdateSourceTrigger من نوع الترقيم UpdateSourceTrigger Enum والموجودة في الفئة Binding تُتيح لك التحكم في تلك الكيفية من خلال أوضاع هي كالتالي:
- PropertyChanged: يتمّ فيه تحديث قيمة الخاصيّة المَصدر كُلّما تمّ تحديث الخاصيّة الهدف.
- LostFocus: يتم تحديث قيمة الخاصيّة المَصدر كُلّما تغيّرت قيمة الخاصيَة الهدف, ولكن فقط عندما يفقد عنصر التحكّم التركيز Focus .
- Explicit: يتم تحديث قيمة الخاصيّة المَصدر كُلّما تغيّرت الخاصيّة الهدف, ولكن فقط عندما تقوم أنت باستدعاء الإجراء BindingExpression.UpdateSource بشكل صريح من خلال الكود. يُمكنك الحصول على كائن من النوع BindingExpression من خلال الإجراء BindingOperations.GetBindingExpression أو استدعاء الإجراء GetBindingExpression لأي كائن من النوع FrameworkContentElement, أو النوع Frameworkelement.
كما يوجد هناك وضع افتراضي بالنسبة لعملية الربط فإن هناك أيصًا وضعًا افتراضيًا بالنسبة لعملية التحديث, على سبيل المثال, فالخاصيّة TextBox.Text افتراضيًا يكون وضع التحديث الخاص بها هو LostFocus .
خيارات الربط Data Binding Options
حتى الآن جميع الأمثلة السابقة تُركّز على الربط بين عنصرين من عناصر WPF, ولكن في أغلب الأحيان في التطبيقات التي تعتمد على قواعد البيانات Data-Driven Applications مصادر البيانات ليست عناصر WPF (ليست أدوات تحكّم واجهة الاستخدام), بل تكون كما ورد في مقدمّة هذا المقال – كائنات غير مرئية – وتحتاج لتمثيلها من خلال عناصر WPF المرئية, ويجب أن يكون متاحًا الوصول إلى خصائص تلك الكائنات , بحيث تكون تلك الخصائص عامّة Public. عند إجراء الربط مع كائنات ليست من عناصر WPF يجب عليك استبعاد استخدام الخاصية ElementName للفئة Binding, وإنما عليك استخدام أحد البدائل التالية:
- الخاصيّة Source: تُمثّل هذه الخاصيّة الارتباط Reference الذي يُشير إلى الكائن المَصدر – بمعنى آخر الكائن الذي يمثل مَصدرًا للبيانات-.
- الخاصيّة RelativeSource: هذه الخاصيّة من النوع System.Windows.Data.RelativeSource Class, وهي تستخدم بغرض الإشارة إلى الكائن نفسه الذي يحتوي على الربط – بمعنى آخر أن الربط يكون من خاصيًة في الكائن المَصدر إلى خاصيّة في الكائن المَصدر نفسه, هذه الخاصيّة مُفيدة عند بناء قوالب أدوات التحكّم Control Templates, و وقوالب البيانات DataTemplates.
- الخاصيّة DataContext للكائن الهدف: عند عدم استخدام أيّ من الخاصيّتين السابقتين, فإن WPF سيقوم بالبحث ضمن شجرة العناصر Elements Tree, بدءًا من النعصر الحالي (العنصر الهدف) , ويقوم بمعاينة الخاصيّة DataContext لكلّ عنصر , ويستخدم أول قيمة ليست Null يجدها كمَصدر للبيانات, إن الخاصيّة DataContext مُفيدة للغاية, إذا كنت تريد أن تقوم بربط خصائص عديدة لنفس الكائن المَصدر مع عدّة عناصر تحكّم WPF, لأنه بوسعك أن تربط الخاصيّة DataContext لأعلى عنصر (العنصر الأبوي الحاوي Container لعناصر التحكّم الباقية) بدلاً من ربطها مع كل عنصر ضمن شجرة العناصر الأبناء.
الخاصيّة Source
يُمكنك التعامل مع الخاصيّة Source بشكل مُباشر, كلّ ما تحتاجه فقط هو أن يكون الكائن مَصدر البيانات جاهزًا للارتباط به, أبسط طريقة يُمكنك من خلالها استخدام هذه الخاصيّة هو أن تقوم بإسناد كائن ستاتيكي لها, قد يكون هذا الكائنن من كتابتك, او احد كائنات مكتبة Microsoft.NET, كما يُوضّح المثال التالي:
PHP كود :
<TextBlock Text="{Binding Source={x:Static SystemFonts.IconFontFamily}, Path=Source}"/>
PHP كود :
<Window.Resources> <FontFamily x:Key="MyFont">Calibri</FontFamily> </Window.Resources>
PHP كود :
<TextBlock Margin="10" Text="Simple Text" FontFamily="{Binding Source{StaticResource MyFont}}" Name="lblSampleText">
الخاصيّة RelativeSource
هناك طريقة أخرى لتحديد الكائن مَصدر البيانات, عبر الخاصيّة Binding.RelativeSource, والتي تُشير إلى ذلك الكائن حسب علاقته مع الكائن الهدف, هذه الخاصيّة من النوع RelativeSource, والذي هو في الأصل مُلحق ترميز (موروث من النوع MarkupExtension), وفيما يلي بعض الاستخدامات الشائعة لهذه الخاصيّة:
- جعل الكائن الهدف هو نفسه الكائن المَصدر:
PHP كود :
{Binding RelativeSource={RelativeSource Self}}
- جعل الكائن المَصدر هو الكائن الذي تحمله الخاصيّة TemplatedParent للكائن الهدف (سيتمّ شرح هذه الخاصيّة لاحقًا في موضوع مُنفصل):
PHP كود :
{Binding RelativeSource={RelativeSource TemplatedParent}}
- جعل الكائن المَصدر هو أقرب عنصر أبوي Parent Element للكائن الهدف, ويكون هذا العنصر الأبوي من نوع مُحدّد:
PHP كود :
{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type desiredType}}}
- جعل الكائن المَصدر هو أقرب عنصر أيويذي الرتبة n للكائن الهدف , ويكون هذا العنصر الأبوي من نوع مُحدّد:
PHP كود :
{Binding RelativeSource={RelativeSource FindAncestor, AncestorLevel=n, AncestorType={x:Type desiredType}}}
استخدام الخاصيّة RelativeSource مُفيد عند بناء قوالب الأدوات Control Templates , كما أن استخدام الخاصية Self مُفيد أيضًا في الكثير من الأحيان عندما تريد ربط خاصيّة لعنصر مع خاصيّة أخرى لنفس العنصر دون الحاجة لذكر اسم ذلك العنصر في تعبير الربط, المثال التالي سيُعطيك فكرة عن كيفية استخدامها, حيث سيتمّ ربط الخاصية ToolTip لعنصر TextBlock مع الخاصية Text لنفس العنصر, وبهذا سيتم عرض قيمة الخاصيّة Text ضمن ToolTip كلّما مررت فوق العنصر:
PHP كود :
<TextBlock Text="Some data" ToolTip="{Binding RelativeSource={RelativeSource Self}, Path=Text}" />
الخاصيّة DataContext
في بعض الأحيان, قد يكون لديك عدة عناصر WPF مرتبطة بنفس الكائن المَصدر, على سبيل المثال, افترض أن الكائن المصَدر سيكون كائنًا من النوع Person ويحتوي على الخصائص التالية: FName, LName, Age, وتريد أن تربط كل خاصيّة منها مع TextBox , وعليه سيكون لديك 3 عناصر TextBox ولتكن بداخل عنصر أبوي من نوع StackPanel, كما يُوضّح المثال التالي, في هذه الحالة قد تقوم بكتابة تعابير ربط طويلة نوعًا ما لكل عنصر TextBox لأنك ستقوم بتحديد الخاصية Source في تعابير الربط تلك, بالإضافة إلى المسار طبعًا:
PHP كود :
<StackPanel> <TextBlock Text="{Binding Source=myPerson, Path=FName}" /> <TextBlock Text="{Binding Source=myPerson, Path=LName}" /> <TextBlock Text="{Binding Source=myPerson, Path=Age}" /> </StackPanel>
PHP كود :
<StackPanel DataContext="{Binding Source=myPerson}">
PHP كود :
<StackPanel DataContext="{Binding Source=myPerson}"> <TextBlock Text="{Binding Path=FName}" /> <TextBlock Text="{Binding Path=LName}" /> <TextBlock Text="{Binding Path=Age}" /> </StackPanel>

