ثني:هل يوجد ربط بيانات برمجي غير مؤلم؟
-
08-06-2019 - |
سؤال
لقد قمت فقط بالقليل من تطوير Flex حتى الآن، لكنني فضلت أسلوب إنشاء عناصر التحكم برمجيًا على ملفات mxml، لأن (و لو سمحت, ، صححني إذا كنت مخطئًا!) لقد أدركت أنه لا يمكنك الحصول على كلا الاتجاهين - أي أن يكون لديك وظيفة الفئة في ملف فئة ActionScript منفصل ولكن لديك العناصر المضمنة المعلنة في mxml.
لا يبدو أن هناك فرقًا كبيرًا من حيث الإنتاجية، لكن ربط البيانات برمجيًا يبدو أقل تافهًا إلى حد ما.لقد ألقيت نظرة على كيفية قيام مترجم mxml بتحويل تعبيرات ربط البيانات.والنتيجة هي مجموعة من عمليات الاسترجاعات التي تم إنشاؤها وخطوط أكثر بكثير من تمثيل mxml.إذن هذا هو السؤال: هل هناك طريقة لربط البيانات برمجياً لا تنطوي على عالم من الأذى؟
المحلول
لا تخافوا من MXML.إنه أمر رائع لوضع وجهات النظر.إذا كتبت بنفسك قابلة لإعادة الاستخدام قد تمنحك كتابتها في ActionScript أحيانًا مزيدًا من التحكم، ولكن بالنسبة لطرق العرض غير القابلة لإعادة الاستخدام، فإن MXML أفضل بكثير.إنه أكثر إيجازًا، والارتباطات سهلة الإعداد للغاية، وما إلى ذلك.
ومع ذلك، فإن الارتباطات في ActionScript الخالص لا تحتاج إلى أن تسبب الكثير من الألم.لن يكون الأمر بهذه البساطة كما هو الحال في MXML حيث يتم تنفيذ الكثير من الأشياء لك، ولكن يمكن القيام بذلك دون بذل الكثير من الجهد.
ما لديك هو BindingUtils
وأساليبها bindSetter
و bindProperty
.أستخدم الخيار الأول دائمًا تقريبًا، لأنني عادةً ما أرغب في القيام ببعض الأعمال أو الاتصال invalidateProperties
عندما تتغير القيم، لا أرغب أبدًا في تعيين خاصية.
ما تحتاج إلى معرفته هو أن هذين يقومان بإرجاع كائن من هذا النوع ChangeWatcher
, ، إذا كنت تريد إزالة الارتباط لسبب ما، فيجب عليك التمسك بهذا الكائن.وهذا ما يجعل الارتباطات اليدوية في ActionScript أقل ملاءمة من تلك الموجودة في MXML.
لنبدأ بمثال بسيط:
BindingUtils.bindSetter(nameChanged, selectedEmployee, "name");
يؤدي هذا إلى إعداد الارتباط الذي سيستدعي الطريقة nameChanged
عندما name
الخاصية على الكائن في المتغير selectedEmployee
التغييرات.ال nameChanged
ستتلقى الطريقة القيمة الجديدة لـ name
الخاصية كوسيطة، لذلك يجب أن تبدو كما يلي:
private function nameChanged( newName : String ) : void
المشكلة في هذا المثال البسيط هي أنه بمجرد إعداد هذا الربط، سيتم تنشيطه في كل مرة تتغير فيها خاصية الكائن المحدد.قيمة المتغير selectedEmployee
قد يتغير، لكن الارتباط لا يزال معدًا للكائن الذي أشار إليه المتغير من قبل.
هناك طريقتان لحل هذا:إما للحفاظ على ChangeWatcher
عاد بواسطة BindingUtils.bindSetter
حول والاتصال unwatch
عليه عندما تريد إزالة الارتباط (ثم إعداد ربط جديد بدلاً من ذلك)، أو ربطه بنفسك.سأعرض لك الخيار الأول أولاً، ثم سأشرح لك ما أعنيه بالارتباط بنفسك.
ال currentEmployee
يمكن تحويله إلى زوج getter/setter وتنفيذه على النحو التالي (إظهار أداة الضبط فقط):
public function set currentEmployee( employee : Employee ) : void {
if ( _currentEmployee != employee ) {
if ( _currentEmployee != null ) {
currentEmployeeNameCW.unwatch();
}
_currentEmployee = employee;
if ( _currentEmployee != null ) {
currentEmployeeNameCW = BindingUtils.bindSetter(currentEmployeeNameChanged, _currentEmployee, "name");
}
}
}
ما يحدث هو أنه عندما currentEmployee
تم تعيين الخاصية لتبدو لمعرفة ما إذا كانت هناك قيمة سابقة، وإذا كان الأمر كذلك، فسيتم إزالة الارتباط لهذا الكائن (currentEmployeeNameCW.unwatch()
)، فإنه يقوم بتعيين المتغير الخاص، وما لم تكن القيمة الجديدة null
يقوم بإعداد رابط جديد لـ name
ملكية.والأهم من ذلك أنه يحفظ ChangeWatcher
تم إرجاعها بواسطة المكالمة الملزمة.
هذا هو نمط الربط الأساسي وأعتقد أنه يعمل بشكل جيد.ومع ذلك، هناك خدعة يمكن استخدامها لجعل الأمر أسهل قليلاً.يمكنك ربط نفسك بدلا من ذلك.بدلاً من إعداد الروابط وإزالتها في كل مرة currentEmployee
تغييرات الخاصية يمكنك جعل نظام الربط يقوم بذلك نيابةً عنك.في الخاص بك creationComplete
المعالج (أو المنشئ أو على الأقل في وقت مبكر) يمكنك إعداد ربط مثل ذلك:
BindingUtils.bindSetter(currentEmployeeNameChanged, this, ["currentEmployee", "name"]);
يؤدي هذا إلى إنشاء ارتباط ليس فقط بـ currentEmployee
الملكية على this
, ، بل أيضًا إلى name
الملكية على هذا الكائن.لذلك في أي وقت إما يغير الطريقة currentEmployeeNameChanged
وسوف يطلق.ليست هناك حاجة لحفظ ChangeWatcher
لأنه لن يلزم إزالة الارتباط أبدًا.
يعمل الحل الثاني في كثير من الحالات، لكنني وجدت أن الحل الأول يكون ضروريًا في بعض الأحيان، خاصة عند العمل مع الارتباطات في فئات غير قابلة للعرض (منذ this
يجب أن يكون مرسل الحدث و currentEmployee
يجب أن تكون قابلة للربط حتى تعمل).
نصائح أخرى
وهي موجودة اعتبارا من اليوم.:)
لقد قمت للتو بإصدار مشروع ربط بيانات ActionScript كمصدر مفتوح: http://code.google.com/p/bindage-tools
BindageTools هو بديل لـ BindingUtils (انظر اللعب على الكلمات هناك؟) يستخدم واجهة برمجة التطبيقات (API) بطلاقة حيث تعلن عن ربط البيانات الخاصة بك في نمط خط الأنابيب:
Bind.fromProperty(person, "firstName")
.toProperty(firstNameInput, "text");
الارتباطات ذات الاتجاهين:
Bind.twoWay(
Bind.fromProperty(person, "firstName"),
Bind.fromProperty(firstNameInput, "text"));
تحويل البيانات الصريحة والتحقق من صحتها:
Bind.twoWay(
Bind.fromProperty(person, "age")
.convert(valueToString()),
Bind.fromProperty(ageInput, "text")
.validate(isNumeric()) // (Hamcrest-as3 matcher)
.convert(toNumber()));
إلخ.هناك الكثير من الأمثلة على الموقع.هناك الكثير من الميزات الأخرى أيضًا، تعال وألق نظرة.--ماثيو
يحرر:واجهات برمجة التطبيقات المحدثة
تتمثل إحدى طرق فصل MXML وActionScript لمكون ما في ملفات منفصلة في القيام بشيء مشابه لرمز ASP.Net 1.x الموجود خلف النموذج.في هذا النموذج، يعد الجزء التعريفي (MXML في هذه الحالة) فئة فرعية من الجزء الأمري (ActionScript).لذلك قد أعلن عن الكود الموجود خلف فصل مثل هذا:
package CustomComponents
{
import mx.containers.*;
import mx.controls.*;
import flash.events.Event;
public class MyCanvasCode extends Canvas
{
public var myLabel : Label;
protected function onInitialize(event : Event):void
{
MyLabel.text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.";
}
}
}
.. والترميز مثل هذا:
<?xml version="1.0" encoding="utf-8"?>
<MyCanvasCode xmlns="CustomComponents.*"
xmlns:mx="http://www.adobe.com/2006/mxml"
initialize="onInitialize(event)">
<mx:Label id="myLabel"/>
</MyCanvasCode>
كما ترون من هذا المثال، من عيوب هذا النهج هو أنه يجب عليك الإعلان عن عناصر التحكم مثل myLabel في كلا الملفين.
هناك طريقة أستخدمها عادةً لاستخدام mxml والبرنامج النصي للعمل معًا:ترث جميع مكونات mxml الخاصة بي من فئة البرنامج النصي للإجراء حيث أقوم بإضافة كود أكثر تعقيدًا.ثم يمكنك الرجوع إلى مستمعي الأحداث المطبقين في هذه الفئة في ملف mxml.
يعتبر،
روث