Гибкий:существует ли безболезненная программная привязка данных?

StackOverflow https://stackoverflow.com/questions/14247

Вопрос

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

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

И т.д.На сайте есть еще много примеров.Там есть и много других функций - приходите посмотреть.--Мэтью

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

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

Как вы можете видеть из этого примера, недостатком такого подхода является то, что вам приходится объявлять элементы управления типа Моя метка в обоих файлах.

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

С уважением,

Рут

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top