ActionScript - список доступа /DataProvider из пользовательского CellRenderer

Приведенный ниже код устанавливает объект List в классе основного контроллера, в котором используется настраиваемое средство визуализации ячеек (класс CustomListCell). класс CustomListCell создает объект Button для ячейки, который будет использоваться для удаления самого себя из DataProvider объекта List.

Как я могу правильно получить доступ к родительскому объекту List из его пользовательского средства визуализации ячеек?

//Controller Class
private function createList():void
 {
 provider = new DataProvider(data);

 list = new List();
 list.width = 200;
 list.height = 400;
 list.rowHeight = 50;
 list.dataProvider = provider;
 list.setStyle("cellRenderer", CustomListCell);
 }

-----

//CustomListCell Class
import fl.controls.Button;

public class CustomListCell extends Sprite implements ICellRenderer
 {     
 public function CustomListCell()
  {
  var button:Button = new Button();
  button.label = "Delete Cell";
  button.addEventListener(MouseEvent_MOUSE_DOWN, deleteCellHandler);
        addChild(button);
  }

 private function deleteCellHandler(evt:MouseEvent):void
  {
  //Access List/DataProvider Here
  }

 //required implemented ICellRenderer functions follow
 }

ОБНОВИТЬ

Ниже приведен мой рабочий пользовательский рендер, который реализует ICellRenderer с компонентом Flash v3 List. dataProvider списка состоит из 2 элементов для каждой ячейки: randomColor и randomNumber.

package
{
//Imports
import fl.controls.Button;
import fl.controls.List;
import fl.controls.listClasses.ICellRenderer; 
import fl.controls.listClasses.ListData;
import flash.display.Sprite;
import flash.events.MouseEvent;
import flash.text.TextField;
import flash.text.TextFieldAutoSize;
import flash.geom.ColorTransform;

//Class
public class TouchListRenderer extends Sprite implements ICellRenderer
    {
    //Properties
    private var cellWidthProperty:Number;
    private var cellHeightProperty:Number;
    private var dataProperty:Object;
    private var listDataProperty:ListData;  
    private var selectedProperty:Boolean;

    //Cell Display Objects
    private var backgroundCanvas:MySprite = new MySprite();
    private var numberTextField:TextField = new TextField();
    private var button:Button = new Button();

    //Constructor
    public function TouchListRenderer()
        {
        }

    //Size Setter (Getter Functions Intentionally Omitted)
    public function setSize(width:Number, height:Number):void
        {
        cellWidthProperty = width;
        cellHeightProperty = height;
        }

    //Data Setter
    public function set data(value:Object):void
        {
        dataProperty = value;
        }

    //Data Getter
    public function get data():Object
        { 
        return dataProperty; 
        }

    //List Data Setter
    public function set listData(value:ListData):void
        { 
        listDataProperty = value;
        }

    //List Data Getter
    public function get listData():ListData
        { 
        return listDataProperty; 
        }

    //Selected Setter
    public function set selected(value:Boolean):void
        { 
        selectedProperty = value;

        layout();
        }

    //Selected Getter
    public function get selected():Boolean
        { 
        return selectedProperty;
        }

    //Size And Layout
    private function layout():void
        {
        var newColor:ColorTransform = new ColorTransform();
        newColor.color = dataProperty.randomColor;

        backgroundCanvas.transform.colorTransform = newColor;
        backgroundCanvas.scaleX = cellWidthProperty / backgroundCanvas.width;
        backgroundCanvas.scaleY = cellHeightProperty / backgroundCanvas.height;

        numberTextField.text = dataProperty.randomNumber;
        numberTextField.autoSize = TextFieldAutoSize.LEFT;
        numberTextField.textColor = 0xFFFFFF;
        numberTextField.x = 50;
        numberTextField.y = cellHeightProperty / 2 - numberTextField.height / 2;
        numberTextField.border = true;
        numberTextField.selectable = false;

        button.label = "Delete";
        button.x = cellWidthProperty - button.width - 50;
        button.y = cellHeightProperty / 2 - button.height / 2;
        button.drawNow();
        button.addEventListener(MouseEvent.MOUSE_DOWN, buttonClickEventHandler);

        addChild(backgroundCanvas);
        addChild(numberTextField);
        addChild(button);
        }

    //Button Click Event Handler
    private function buttonClickEventHandler(evt:MouseEvent):void
        {
        List(listDataProperty.owner).removeItemAt(listDataProperty.index);
        }

    //Style Setter
    public function setStyle(style:String, value:Object):void
        {
        }

    //Mouse State Setter
    public function setMouseState(state:String):void
        {
        }
    } 
} 

package
{
import flash.display.Sprite;

public class MySprite extends Sprite
    {
    public function MySprite()
        {
        graphics.beginFill(0xFF0000);
        graphics.drawRect(0, 0, 10, 10);
        graphics.endFill();
        }
    }
}

2 ответа

Решение

Тьфу! ответ был передо мной все время! в следующий раз напомни мне проверить документы:

List(listData.owner)

fl.controls.listClasses.ListData.owner

Есть несколько способов сделать это.

Вот очень хакерское решение: используйте значок, и пусть этот значок отправляет событие close.

Идея заключается в том, что вы поместите собственный мувиклип в каждую ячейку списка в виде значка. Этот значок отправит событие с индексом ячейки, по которой вы щелкнули, чтобы вы могли удалить его.

1-й шаг: создание базового пользовательского события для передачи индекса ячейки через:

package{

    import flash.events.Event;

    public class CloseEvent extends Event{

        public static const CLOSE:String = 'close';
        public var index:int;

        public function CloseEvent(type:String,bubbles:Boolean = true,cancelable:Boolean=true){
            super(type,bubbles,cancelable);
        }

    }

}

2-й шаг: нарисуйте значок закрытия или что-то, преобразуйте его в MovieClip и экспортируйте для Actionscript

3-й шаг: добавьте прослушиватель событий, чтобы отправлять пользовательское событие при нажатии на значок закрытия.

Внутри значка закрытия Movie Clip я поместил следующие действия:

import fl.controls.listClasses.CellRenderer;

//setup click
buttonMode = true;
if(parent) parent.mouseChildren = true;
addEventListener(MouseEvent.MOUSE_DOWN,dispatchClose);
//setup event
var closeEvent:CloseEvent = new CloseEvent(CloseEvent.CLOSE,true);
if(parent) closeEvent.index = CellRenderer(parent).listData.index;
//listen to click and pass on
function dispatchClose(event:MouseEvent):void {
    dispatchEvent(closeEvent);
}

Очень простые вещи, слушайте мышку вниз, создавайте событие, устанавливайте индекс и отправляйте это событие по щелчку. Значок добавляется в средство визуализации ячеек, поэтому для ячейки отображается ее родительский объект, в котором среди прочих имеется свойство listData, в котором содержится индекс ячейки.

Итак, вот как выглядит тестовый фрагмент:

import fl.data.DataProvider;

var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1),icon:Close});
ls.dataProvider = dp;

addEventListener(CloseEvent.CLOSE,deleteItem);
function deleteItem(event:CloseEvent):void {
    ls.removeItemAt(event.index);
}

Так как CloseEvent всплывает, мы можем поймать его снаружи с помощью значка средства визуализации ячеек и указать списку удалить элемент по этому индексу. Это можно сделать с помощью значка, но необходимо будет "подняться" вверх по иерархии до самого списка, и это уже довольно странно.

Я сделал это, потому что я, вероятно, был так же ленив, как @TheDarkIn1978:P, для реализации функций ICellRenderer. Затем я снова посмотрел на код вопроса и не понял, почему пользовательская ячейка расширяет Sprite, когда CellRenderer уже реализует функции ICellRenderer.

Итак, вот моя попытка сделать это в менее хакерской манере:

package{

    import fl.controls.*;
    import fl.controls.listClasses.*;
    import fl.data.*;
    import flash.events.*;

    public class SCListCell extends CellRenderer implements ICellRenderer{

        protected var closeButton:Button;
        protected var closeEvent:CloseEvent;

        override protected function configUI():void {
            super.configUI();
            closeButton = new Button();
            closeButton.label = 'x';
            closeButton.buttonMode = true;
            closeButton.setSize(30,20);
            closeButton.drawNow();
            closeButton.addEventListener(MouseEvent.CLICK,close);
            addChild(closeButton);
            closeEvent = new CloseEvent(CloseEvent.CLOSE);
        }

        private function close(event:MouseEvent):void{
            closeEvent.index = listData.index;
            dispatchEvent(closeEvent);
        }

        override protected function drawLayout():void{
            mouseChildren = true;
            closeButton.x = width-closeButton.width;
        }

    }

}

Для передачи индекса использовался тот же метод CloseEvent, а пользовательская ячейка имеет прямой доступ к объекту listData для извлечения индекса, поэтому фрагмент кода выглядит следующим образом:

import fl.data.DataProvider;

var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1)});
ls.dataProvider = dp;

addEventListener(CloseEvent.CLOSE,deleteItem);
function deleteItem(event:CloseEvent):void {
    ls.removeItemAt(event.index);
}

ls.setStyle('cellRenderer',SCListCell);

Итак, чтобы ответить на ваш вопрос:

Как я могу правильно получить доступ к родительскому объекту List из его пользовательского средства визуализации ячеек?

Вы можете использовать свойство listData средства визуализации ячеек. Вы можете, если хотите, но это означает пройти несколько уровней:

package{

    import fl.controls.*;
    import fl.controls.listClasses.*;
    import fl.data.*;
    import flash.events.*;

    public class SCListCell extends CellRenderer implements ICellRenderer{

        protected var closeButton:Button;

        override protected function configUI():void {
            super.configUI();
            closeButton = new Button();
            closeButton.label = 'x';
            closeButton.buttonMode = true;
            closeButton.setSize(30,20);
            closeButton.drawNow();
            closeButton.addEventListener(MouseEvent.CLICK,close);
            addChild(closeButton);
        }

        private function close(event:MouseEvent):void{
            List(this.parent.parent.parent).removeItemAt(listData.index);
        }

        override protected function drawLayout():void{
            mouseChildren = true;
        closeButton.x = width-closeButton.width;
        }

    }

}

Что оставляет часть создания списка такой простой, как:

import fl.data.DataProvider;

var dp:DataProvider = new DataProvider();
for(var i:int = 0 ; i < 30 ; i++) dp.addItem({label:'item'+(i+1)});
ls.dataProvider = dp;

ls.setStyle('cellRenderer',SCListCell);

CloseEvent не требуется в этом случае.

НТН

Другие вопросы по тегам