2008-08-18 15 views
13

मैं केवल फ्लेक्स विकास का एक सा अब तक किया है, लेकिन मैं प्रोग्राम के रूप में MXML फ़ाइलों पर नियंत्रण बनाने के दृष्टिकोण को प्राथमिकता दिया है, क्योंकि (और , मुझे सही करें यदि मैं गलत हूँ!) मैं एकत्रित की हैं कि आपके पास यह दोनों तरीकों से नहीं हो सकता है - इसका कहना है कि कक्षा की कार्यक्षमता एक अलग एक्शनस्क्रिप्ट क्लास फ़ाइल में है लेकिन इसमें निहित तत्व एमएक्सएमएल में घोषित हैं।फ्लेक्स: दर्द रहित प्रोग्रामेटिक डेटा बाइंडिंग मौजूद है?

वहाँ एक अंतर उत्पादकता के लिहाज से की ज्यादा होना प्रतीत नहीं होता है, लेकिन प्रोग्राम के रूप में बाध्यकारी कर डेटा तुच्छ से कुछ हद तक कम लगती है। मैंने देखा कि एमएक्सएमएल कंपाइलर डेटा बाध्यकारी अभिव्यक्तियों को कैसे बदलता है। परिणाम जेनरेट कॉलबैक का एक गुच्छा है और एमएक्सएमएल प्रतिनिधित्व में बहुत अधिक लाइनें हैं। तो यहां सवाल है: प्रोग्राम बाध्यकारी प्रोग्रामिंग करने का कोई तरीका है जिसमें चोट की दुनिया शामिल नहीं है?

उत्तर

29

MXML की डरो मत। विचारों को बिछाने के लिए यह बहुत अच्छा है। आप लिखते हैं तो उन्हें ActionScript में लेखन अपनी खुद की पुन: प्रयोज्य घटकों कभी कभी तुम एक छोटे से अधिक नियंत्रण दे सकता है, लेकिन गैर पुन: प्रयोज्य विचारों MXML के लिए तो ज्यादा बेहतर है। इसे और अधिक संक्षिप्त

हालांकि, शुद्ध ActionScript में बाइंडिंग कि एक दर्द की ज्यादा होने की जरूरत नहीं है, बाइंडिंग स्थापित करने के लिए extemely आसान कर रहे हैं, आदि। यह एमएक्सएमएल में जितना आसान नहीं होगा, जहां आपके लिए बहुत सी चीजें की जाती हैं, लेकिन इसे बहुत अधिक प्रयास के साथ नहीं किया जा सकता है।

आपके पास BindingUtils है और इसकी विधियां bindSetter और bindProperty है। मैं लगभग हमेशा, पूर्व का उपयोग के बाद से मैं आमतौर पर कुछ काम करना चाहते हैं, या invalidateProperties फोन जब मान बदलते हैं, मैं लगभग कभी नहीं सिर्फ एक गुण सेट करना चाहते हैं।

आपको यह जानने की आवश्यकता है कि यदि आप किसी कारण से बाध्यकारी को हटाना चाहते हैं, तो इन दोनों को ChangeWatcher प्रकार का ऑब्जेक्ट लौटाता है, तो आपको इस ऑब्जेक्ट को पकड़ना होगा। यह एक्शनस्क्रिप्ट में मैन्युअल बाइंडिंग को एमएक्सएमएल की तुलना में थोड़ा कम सुविधाजनक बनाता है।

को एक सरल उदाहरण के साथ शुरू करते हैं:

BindingUtils.bindSetter(nameChanged, selectedEmployee, "name"); 

यह सेट एक बाध्यकारी है कि विधि nameChanged फोन करेगा जब चर selectedEmployee परिवर्तन में वस्तु पर name संपत्ति। nameChanged विधि एक तर्क के रूप name संपत्ति के नए मूल्य प्राप्त होगा, तो यह इस तरह दिखना चाहिए:

private function nameChanged(newName : String) : void 

इस सरल उदाहरण के साथ समस्या यह है कि इस बंधन हर बार सक्रिय होगा एक बार आप की स्थापना की है है निर्दिष्ट वस्तु की संपत्ति बदल जाती है। परिवर्तनीय selectedEmployee का मान बदल सकता है, लेकिन बाइंडिंग अभी भी ऑब्जेक्ट के लिए सेट की गई है जो चर पहले की ओर इशारा करता है।

इस को हल करने के दो तरीके हैं: या तो ChangeWatcher आसपास BindingUtils.bindSetter द्वारा वापस रखने के लिए और उस पर unwatch फोन जब आप निकालना चाहते हैं के लिए बाध्य (और फिर बजाय एक नया बंधन की स्थापना), या अपने आप को करने के लिए बाध्य। मैं आपको पहले विकल्प को पहले दिखाऊंगा, और फिर समझाऊंगा कि मेरा मतलब बाध्यकारी है।

currentEmployee एक गेटर/सेटर जोड़ी में बनाया जा सकता है और इस तरह से लागू किया (केवल सेटर दिखाते हुए):

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()) के लिए बाध्यकारी को हटा देता है, तो यह निजी चर सेट करता है, और जब तक नया मान nullname संपत्ति के लिए एक नया बाध्यकारी सेट करता है। सबसे महत्वपूर्ण बात यह है कि बाध्यकारी कॉल द्वारा ChangeWatcher लौटा दी गई है।

यह एक मूल बाध्यकारी पैटर्न है और मुझे लगता है कि यह ठीक काम करता है। हालांकि, एक चाल है जिसका उपयोग इसे थोड़ा आसान बनाने के लिए किया जा सकता है। आप इसके बजाय खुद से बांध सकते हैं। currentEmployee संपत्ति परिवर्तन में हर बार बाइंडिंग को स्थापित करने और निकालने के बजाय आप बाध्यकारी प्रणाली को अपने लिए कर सकते हैं। अपने creationComplete हैंडलर (या निर्माता या जल्दी कम से कम कुछ समय) में आप तो जैसे एक बाध्यकारी सेट कर सकते हैं:

BindingUtils.bindSetter(currentEmployeeNameChanged, this, ["currentEmployee", "name"]); 

यह एक बाध्यकारी न केवल this पर currentEmployee संपत्ति के लिए, लेकिन यह भी करने के लिए name संपत्ति सेट इस वस्तु पर। इसलिए किसी भी समय या तो currentEmployeeNameChanged विधि को बदल दिया जाएगा। ChangeWatcher को सहेजने की कोई आवश्यकता नहीं है क्योंकि बाध्यकारी को कभी भी हटाया नहीं जाना चाहिए।

दूसरा समाधान कई मामलों में काम करता है, लेकिन मुझे लगता है कि पहले एक कभी कभी आवश्यक है, खासकर जब गैर दृश्य कक्षाओं में बाइंडिंग के साथ काम (मिल गया है के बाद से this एक घटना डिस्पैचर हो गया है और currentEmployee हो गया है काम करने के लिए इसके लिए बाध्यकारी)।

+0

ग्रेट लिखित। यह बहुत उपयोगी था। धन्यवाद! – airportyh

+0

वास्तव में महान लिखो। – Kevin

+0

वास्तव में बहुत बढ़िया लेखन! एक त्वरित सवाल पहले समाधान के लिए एक आसान दृष्टिकोण नहीं होगा यह जांचने के लिए कि क्या वर्तमान कर्मचारी नौकायन शून्य है? यदि यह शून्य नहीं है, तो बाध्यकारी मौजूद है, इसलिए currentEmployeeNameCW.unwatch() को कॉल करें। एक अधिक सामान्यीकृत और अभी भी बहुत संक्षिप्त समाधान की तरह लगता है। – rinogo

2

अलग-अलग फ़ाइलों में एक घटक के लिए एमएक्सएमएल और एक्शनस्क्रिप्ट को अलग करने का एक तरीका मॉडल के पीछे एएसपी.Net 1.x कोड के समान कुछ करना है। इस मॉडल में घोषणात्मक हिस्सा (इस मामले में एमएक्सएमएल) अनिवार्य भाग (एक्शनस्क्रिप्ट) का उप-वर्ग है। तो मैं इस तरह एक वर्ग के लिए पीछे कोड की घोषणा हो सकती है:

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> 

आप इस उदाहरण से देख सकते हैं, इस दृष्टिकोण का एक disadvatage है कि आपको दोनों फ़ाइलों में myLabel जैसे नियंत्रण घोषित करना होगा।

+0

ऐसा करने का अच्छा कारण यह है कि यह फ्लेक्स डिज़ाइन व्यू को तोड़ता नहीं है। यदि आपको डिज़ाइन व्यू (मेरे जैसे) के लिए बहुत अधिक परवाह नहीं है तो विरासत करना दूसरे तरीके से निपटना बहुत आसान है। आपको अपने .as वर्ग में एमएक्सएमएल बच्चों को पूर्व-घोषित (और सिंक में रखना) नहीं है। इसके अलावा यह और अधिक "सही" लगता है। एक दृश्य लें, और इसमें कार्यक्षमता जोड़ें। –

+0

ऐसा न करें ... यह आपको व्यू के लिए आवश्यक कक्षाओं की संख्या दोगुना कर देगा। – Clintm

0

एक तरीका है कि मैं आमतौर पर एमएक्सएमएल और एक्शन स्क्रिप्ट का उपयोग करने के लिए उपयोग करता हूं: मेरे सभी एमएक्सएमएल घटक एक एक्शन स्क्रिप्ट क्लास से प्राप्त होते हैं जहां मैं अधिक जटिल कोड जोड़ता हूं। फिर आप mxml फ़ाइल में इस वर्ग में लागू इवेंट श्रोताओं को संदर्भित कर सकते हैं।

सादर,

रुथ

8

यह आज के रूप में मौजूद है। http://code.google.com/p/bindage-tools

BindageTools है BindingUtils के लिए एक विकल्प (वहाँ शब्दों पर खेलने देखें: :)

मैं बस अपना ActionScript डेटा बाइंडिंग परियोजना के रूप में खुला स्रोत जारी किया गया?) एक धाराप्रवाह एपीआई जहाँ आप एक पाइप लाइन शैली में अपने डेटा बाइंडिंग की घोषणा का उपयोग करता है:

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())); 

आदि साइट पर बहुत सारे उदाहरण हैं। बहुत सारी अन्य विशेषताएं भी हैं- एक नज़र डालें। - मैथ्यू

संपादित करें: अद्यतन एपीआई

+0

किसी को ऐसा करने के लिए यह बहुत अच्छा है, शुद्ध AS3 तरीके में बहुत धन्यवाद ~ – davyzhang

+0

मेरी खुशी, खुशी है कि आप इसे उपयोगी पाते हैं। – qualidafial

संबंधित मुद्दे