2008-08-18 12 views
13

지금까지 Flex 개발을 조금 해봤지만 mxml 파일을 통해 프로그래밍 방식으로 컨트롤을 만드는 방법을 선호했기 때문에 (을 수정하십시오. 내가 틀렸다면 수정하십시오!) 나는 모았습니다. 두 가지 방법이있을 수 없다는 것입니다. 즉, 별도의 ActionScript 클래스 파일에 클래스 기능이 있지만 mxml에 선언 된 요소가 포함되어 있어야합니다.플렉스 : 고통없는 프로그래밍 방식의 데이터 바인딩이 있습니까?

생산성 측면에서 많은 차이가있는 것 같지 않지만 프로그래밍 방식으로 데이터 바인딩을하는 것은 다소 단순한 것 같습니다. mxml 컴파일러가 데이터 바인딩 표현식을 변환하는 방법을 살펴 보았습니다. 결과는 생성 된 콜백과 mxml 표현보다 훨씬 많은 라인을 생성합니다. 그래서 여기에 질문 : 거기에 상처의 세계를 포함하지 않는 프로그래밍 방식으로 데이터 바인딩을 할 수있는 방법은 무엇입니까?

답변

29

MXML을 두려워하지 마십시오. 보기 배치에 좋습니다. 재사용 가능 구성 요소를 작성한 다음 ActionScript로 작성하면 가끔씩 컨트롤을 줄 수 있지만 재사용이 불가능한보기의 경우 MXML이 훨씬 좋습니다. 더 간결하고 바인딩은 매우 쉽게 설정할 수 있습니다.

그러나 순수 ActionScript의 바인딩은 그리 큰 고통이 아니어도됩니다. 많은 일이 당신을 위해 행해지는 MXML만큼이나 간단하지는 않으나 너무 많은 노력을 기울이지 않아도됩니다.

당신이 가지고있는 것은 BindingUtils이며 그 방법은 bindSetterbindProperty입니다. 거의 항상 전 (前者)을 사용합니다. 보통 일을하고 싶거나 invalidateProperties으로 전화하면 값이 변하면 거의 속성을 설정하지 않으려 고합니다.

당신이 알아야 할 것은이 두 가지가 ChangeWatcher 유형의 객체를 반환한다는 것입니다. 어떤 이유로 바인딩을 제거하려면이 객체를 고정해야합니다. 이것은 ActionScript의 수동 바인딩을 MXML의 수동 바인딩보다 약간 덜 편리하게 만듭니다.

간단한 예제부터 시작하자 :

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"]); 

이 바인딩 thiscurrentEmployee 재산뿐만 아니라에뿐만 아니라 name 속성을 설정합니다 이 개체에. 언제든지 어느 쪽이든 방법을 변경하면 currentEmployeeNameChanged가 호출됩니다. 바인딩을 절대로 삭제할 필요가 없으므로 ChangeWatcher을 저장할 필요가 없습니다.

두 번째 솔루션은 대부분의 경우 작동하지만 첫 번째 것이 때때로 필요합니다 (특히 비 시각 클래스의 바인딩 작업을 할 때) (this이 이벤트 디스패처 여야하고 currentEmployee이되어야 함) 그것을 위해 묶을 수있는).

+0

큰 글. 이것은 매우 도움이되었습니다. 감사! – airportyh

+0

대단히 글을 쓴다. – Kevin

+0

대단한 글 쓰기! 빠른 질문. 첫 번째 솔루션에 대한 더 간단한 접근 방식은 currentEmployeeNameCW가 null인지 단순히 확인하는 것이 아니겠습니까? null가 아닌 경우 바인딩이 있으므로 currentEmployeeNameCW.unwatch()를 호출합니다. 좀 더 일반화되고 여전히 간결한 솔루션처럼 보입니다. – rinogo

2

구성 요소의 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> 

이 접근 방식의 disadvatage이다 두 파일에서 myLabel과 같은 컨트롤을 선언해야합니다.

+0

이렇게하는 이유는 플렉스 디자인보기를 손상시키지 않기 때문입니다. 나 같은 디자인 뷰를별로 신경 쓰지 않는다면 상속을 다른 방법으로 처리하는 것이 훨씬 쉽습니다. .as 클래스의 mxml 하위 항목을 미리 선언하고 동기화 할 필요가 없습니다. 또한 더 "옳은"느낌. 시각적으로 기능을 추가하십시오. –

+0

이렇게하지 않으면 ...보기에 필요한 클래스 수를 두 배로 늘릴 수 있습니다. – Clintm

0

나는 보통 mxml과 액션 스크립트를 함께 사용하는 방법이 있습니다. 모든 mxml 구성 요소는 더 복잡한 코드를 추가하는 액션 스크립트 클래스에서 상속됩니다. 그런 다음이 클래스에 구현 된 이벤트 리스너를 mxml 파일에서 참조 할 수 있습니다.

감사합니다,

루스

8

그것은 오늘로 존재한다. http://code.google.com/p/bindage-tools

BindageTools BindingUtils에 대한 대안이 (이 단어 놀이를 볼 수있다 : :)

난 그냥 내 ActionScript 데이터 바인딩 프로젝트로 오픈 소스를 공개?)는 파이프 라인 스타일에 데이터 바인딩을 선언 유창하게 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())); 

기타 이 사이트에는 더 많은 예제가 있습니다. 다른 많은 기능도 있습니다. 한 번 살펴 보겠습니다. - 매튜

편집 : 업데이트 된 API

+0

누군가가 이것을 한 것은 대단합니다. 순수한 as3 방법 덕분에 많이 ~ – davyzhang

+0

내게 기쁨, 다행 이니 유용하다는 것을 느낍니다. – qualidafial