Объединить данные в фильтрованную коллекцию ArrayCollection (может быть, используя IViewCursor или localIndex?) - PullRequest
1 голос
/ 05 января 2012

У меня вопрос по Flex, который не так прост, как кажется на первый взгляд.

По крайней мере, я борюсь с ней 1 неделю.

Я подготовил тестовый пример и снимок экрана.

Вопрос: как объединить данные (поступающие неоднократно с сервера) в отфильтрованную коллекцию ArrayCollection?

Скриншот:

screenshot

TestCase.mxml (просто поместите его в проект Flash Builder 4.6):

<?xml version="1.0" encoding="utf-8"?>
<s:Application 
    xmlns:fx="http://ns.adobe.com/mxml/2009"
    xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Declarations>
        <s:RadioButtonGroup id="_group" itemClick="radioClicked(event);"/>
    </fx:Declarations>

    <fx:Script>
        <![CDATA[
            import mx.collections.ArrayCollection;
            import mx.events.ItemClickEvent;

            [Bindable]
            private var _data:ArrayCollection = new ArrayCollection();

            private const DATA1:Array = [10,20,30,40,50]; 
            private const DATA2:Array = [10,20,30,50]; 
            private const DATA3:Array = [10,20,30,40,50,60]; 
            private const DATA4:Array = [10,20,30,35,40,50]; 
            private const DATA5:Array = [];
            private const DATA6:Array = [25,45]; 

            private function merge(data:Array):void {
                var i:int;
                var j:int;

                // 1) remove items missing in data from _data
                found1:
                for (i = _data.length - 1; i >= 0; i--) {
                    for (j = data.length - 1; j >= 0; j--) {
                        if (_data[i] == data[j])
                            continue found1;
                    }
                    _data.removeItemAt(i);
                }

                // 2) add items appeared in data to _data
                found2:
                for (j = 0; j < data.length; j++) {
                    for (i = 0; i < _data.length; i++) {
                        if (_data[i] == data[j])
                            continue found2;
                    }
                    _data.addItem(data[j]);
                }
            }

            private function radioClicked(event:ItemClickEvent):void {
                if (event.label.indexOf('Odd') == 0) {
                    _data.filterFunction = filterOdd; 
                } else if (event.label.indexOf('Even') == 0) {
                    _data.filterFunction = filterEven; 
                } else {
                    _data.filterFunction = null; 
                }
                _data.refresh();
            }

            private function filterOdd(item:Object):Boolean {
                var i:uint = item as uint;
                return (i % 2 == 1);
            }

            private function filterEven(item:Object):Boolean {
                var i:uint = item as uint;
                return (i % 2 == 0);
            }
        ]]>
    </fx:Script>

    <s:layout>
        <s:VerticalLayout gap="20" />
    </s:layout>

    <s:HGroup verticalAlign="baseline">
        <s:Label text="FILTER:" />
        <s:RadioButton groupName="_group" label="All" selected="true" />
        <s:RadioButton groupName="_group" label="Odd" />
        <s:RadioButton groupName="_group" label="Even" />
    </s:HGroup>

    <s:List id="_list" dataProvider="{_data}" />

    <s:Button id="_btn1" label="{DATA1.join()}" click="merge(DATA1)" />
    <s:Button id="_btn2" label="{DATA2.join()}" click="merge(DATA2)" />
    <s:Button id="_btn3" label="{DATA3.join()}" click="merge(DATA3)" />
    <s:Button id="_btn4" label="{DATA4.join()}" click="merge(DATA4)" />
    <s:Button id="_btn5" label="{DATA5.join()}" click="merge(DATA5)" />
    <s:Button id="_btn6" label="{DATA6.join()}" click="merge(DATA6)" />

</s:Application>

Проблема заключается в том, что когда ArrayCollection _data имеет значение отфильтровано (поскольку установлен флажок «Even»), то второй цикл в тестовом примере (для добавления новых элементов) добавляет элементы («35») снова и снова - потому что он фильтруется и, таким образом, не виден .

Пожалуйста, предложите решение - с исходным кодом.

Пожалуйста, не отправляйте меня в такие документы, как IViewCursor или ListCollectionView.localIndex - поскольку многие из них я прочитал за последнюю неделю.

Спасибо!

1 Ответ

2 голосов
/ 05 января 2012

Попробуйте использовать ArrayCollection свойство source следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" xmlns:s="library://ns.adobe.com/flex/spark">

    <fx:Declarations>
        <s:RadioButtonGroup id="filterGroup" change="radioClicked(event)" />
    </fx:Declarations>

    <fx:Script>
    <![CDATA[
        import mx.collections.ArrayCollection;

        private const DATA1:Array = [ 10, 20, 30, 40, 50 ];
        private const DATA2:Array = [ 10, 20, 30, 50 ];
        private const DATA3:Array = [ 10, 20, 30, 40, 50, 60 ];
        private const DATA4:Array = [ 10, 20, 30, 35, 40, 50 ];
        private const DATA5:Array = [];
        private const DATA6:Array = [ 25, 45 ];

        [Bindable]
        private var _data:ArrayCollection = new ArrayCollection();

        private function filterEven(item:Object):Boolean
        {
            var i:uint = item as uint;
            return (i % 2 == 0);
        }

        private function filterOdd(item:Object):Boolean
        {
            var i:uint = item as uint;
            return (i % 2 == 1);
        }

        private function merge(data:Array):void
        {
            var i:int;
            var j:int;


            var sourceData:Array = _data.source;
            // 1) remove items missing in data from _data
            found1: for (i = sourceData.length - 1; i >= 0; i--)
            {
                for (j = data.length - 1; j >= 0; j--)
                {
                    if (sourceData[i] == data[j])
                        continue found1;
                }
                var index:int = _data.getItemIndex(sourceData[i]);
                if (index > -1)
                    _data.removeItemAt(index); // remove visible items
                else
                    sourceData.splice(i, 1); // remove hidden (filtered) items
            }

            // 2) add items appeared in data to _data
            found2: for (j = 0; j < data.length; j++)
            {
                for (i = 0; i < sourceData.length; i++)
                {
                    if (sourceData[i] == data[j])
                        continue found2;
                }
                _data.addItem(data[j]);
            }
        }

        private function radioClicked(event:Event):void
        {
            switch (filterGroup.selection)
            {
                case allButton:
                {
                    _data.filterFunction = null;
                    break;
                }
                case oddButton:
                {
                    _data.filterFunction = filterOdd;
                    break;
                }
                case evenButton:
                {
                    _data.filterFunction = filterEven;
                    break;
                }
            }
            _data.refresh();
        }
    ]]>
    </fx:Script>

    <s:layout>
        <s:VerticalLayout gap="20" />
    </s:layout>

    <s:HGroup verticalAlign="baseline">
        <s:Label text="FILTER:" />
        <s:RadioButton id="allButton" group="{filterGroup}" label="All" selected="true" />
        <s:RadioButton id="oddButton" group="{filterGroup}" label="Odd" />
        <s:RadioButton id="evenButton" group="{filterGroup}" label="Even" />
    </s:HGroup>

    <s:List dataProvider="{_data}" id="_list" />

    <s:Button click="merge(DATA1)" id="_btn1" label="{DATA1.join()}" />
    <s:Button click="merge(DATA2)" id="_btn2" label="{DATA2.join()}" />
    <s:Button click="merge(DATA3)" id="_btn3" label="{DATA3.join()}" />
    <s:Button click="merge(DATA4)" id="_btn4" label="{DATA4.join()}" />
    <s:Button click="merge(DATA5)" id="_btn5" label="{DATA5.join()}" />
    <s:Button click="merge(DATA6)" id="_btn6" label="{DATA6.join()}" />

</s:Application>

И пара советов по использованию RadioButton и RadioButtonGroup:

  • Не использовать события кликов для обработки изменений. Это отключает возможность управления кнопками другим способом (например, с клавиатуры). Вместо этого используйте change.
  • Если вы используете RadioButtonGroup, лучше ссылаться на group, а не groupName. Это дает вам возможность проверить проблемы во время компиляции (представьте некоторые опечатки в имени группы).
  • Не проверять выбранную кнопку на ярлыке. Вы можете опечатать название метки или можете поменять метку и т. Д., И компилятор не может вам помочь.
...