Flex: существует безболезненная программная привязка данных? - PullRequest
13 голосов
/ 18 августа 2008

До сих пор я только немного занимался разработкой Flex, но я предпочел подход программного создания элементов управления для файлов mxml, потому что (и пожалуйста , исправьте меня, если я ошибаюсь! Я понял, что у вас не может быть обоих способов - то есть иметь функциональные возможности класса в отдельном файле классов ActionScript, но содержать элементы, объявленные в mxml.

По производительности, похоже, нет большой разницы, но программное связывание данных кажется несколько менее тривиальным. Я взглянул на то, как компилятор mxml преобразует выражения привязки данных. В результате получается множество сгенерированных обратных вызовов и намного больше строк, чем в представлении mxml. Итак, вот вопрос: существует ли способ программно связывать данные, который не затрагивает мир вреда?

Ответы [ 4 ]

29 голосов
/ 18 августа 2008

Не бойся 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 может быть преобразован в пару геттер / установщик и реализован следующим образом (только показывает установщик):

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 должен быть привязан, чтобы он работал).

8 голосов
/ 02 апреля 2011

существует с сегодняшнего дня. :)

Я только что выпустил свой проект привязки данных 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()));

Etc. На сайте есть еще много примеров. Там также много других функций - приходите посмотреть. --Matthew

Редактировать: обновленные API

2 голосов
/ 30 августа 2008

Один из способов разделить 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 в обоих файлах.

0 голосов
/ 04 февраля 2009

я обычно использую способ совместного использования mxml и сценария действия: все мои компоненты mxml наследуются от класса сценария действия, в который я добавляю более сложный код. Затем вы можете обратиться к обработчикам событий, реализованным в этом классе, в файле mxml.

С уважением,

Ruth

...