Так случилось, что фильтрация коллекций ни разу не беспокоила меня. А тут коллега задал вопрос, который послужил толчком к тому, что вы сейчас прочитаете. =)
Коллеге необходимо показать во view отфильтрованную ArrayCollection. Сама ArrayCollection находится в модели. Когда во view применяется фильтр, то данные модели очень сильно выглядят измененными. Что делать? Как быть?
Конечно, мы с вами знаем, что данные на самом деле не меняются. source коллекции так и остается исходным. Но не работать же в модели с source?
Конечно, не работать! И уж конечно, не делать копии коллекций! Тут спасибо Константинеру за наводку. =)
Можно использовать ListCollectionView в качестве обертки нашей исходной коллекции уже на уровне view. Тогда довольная модель работает с ArrayCollection, как и прежде, а view показывает, что захочет.
В качестве примера использую пример из доков Adobe для фильтрации коллекций.
Пример такой:
XML:
| <?xml version="1.0"?> |
| |
| <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="600"> |
| <mx:Script> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| </mx:Script> |
| |
| |
| <mx:ArrayCollection id="myAC"> |
| <mx:Array id="myArray"> |
| <mx:Object label="LA" data="Baton Rouge"/> |
| <mx:Object label="NH" data="Concord"/> |
| <mx:Object label="TX" data="Austin"/> |
| <mx:Object label="MA" data="Boston"/> |
| <mx:Object label="AZ" data="Phoenix"/> |
| <mx:Object label="OR" data="Salem"/> |
| <mx:Object label="FL" data="Tallahassee"/> |
| <mx:Object label="MN" data="Saint Paul"/> |
| <mx:Object label="NY" data="Albany"/> |
| </mx:Array> |
| </mx:ArrayCollection> |
| |
| <!-- Buttons to filter, sort, or reset the view in the second ComboBox |
| control. --> |
| <mx:HBox width="100%"> |
| <mx:Button id="sortButton" label="Sort" click="sortAC();"/> |
| <mx:Button id="filterButton" label="Filter" click="filterAC();"/> |
| <mx:Button id="resetButton" label="Reset" click="resetAC();"/> |
| </mx:HBox> |
| <mx:VBox width="550" height="143" borderStyle="solid" paddingTop="10" paddingLeft="10"> |
| <mx:Label text="This box retains original order and contents of the Array:"/> |
| <!-- A ComboBox populated by the underlying Array object. |
| This control shows that Array retains its original order. --> |
| <mx:ComboBox id="cb2" rowCount="10" dataProvider="{myArray}"/> |
| <mx:HRule/> |
| <mx:Label text="This box reflects the changes to the Array:"/> |
| |
| <mx:ComboBox id="cb1" rowCount="10" dataProvider="{myAC}"/> |
| </mx:VBox> |
| </mx:Application> |
Тут у нас два выпадающих списка: один с source коллекции, а второй с самой коллекцией.
Можно отсортировать, отфильтровать коллекцию и посмотреть, что будет.
После выполнения метода filterAC наша коллекция уже сама не своя, ее прямо не узнать.
Что же мы делаем? Тут и далее использован беглый стиль программирования, потому что все-таки пример. =)
Добавляем обертку для коллекции:
Code:
| [Bindable] |
| private var wrapper:ListCollectionView; |
После создания приложения создаем эту нашу обертку:
Code:
| creationComplete="wrapper=new ListCollectionView(myAC)" |
Фильтруем уже эту обертку, ее же показываем во втором выпадающем списке.
Добавляем новый выпадающий список для нашей родной коллекции.
Вот как выглядит код после изменений:
XML:
| <?xml version="1.0"?> |
| |
| <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" width="600" |
| creationComplete="wrapper=new ListCollectionView(myAC)"> |
| <mx:Script> |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| </mx:Script> |
| |
| |
| <mx:ArrayCollection id="myAC"> |
| <mx:Array id="myArray"> |
| <mx:Object label="LA" data="Baton Rouge"/> |
| <mx:Object label="NH" data="Concord"/> |
| <mx:Object label="TX" data="Austin"/> |
| <mx:Object label="MA" data="Boston"/> |
| <mx:Object label="AZ" data="Phoenix"/> |
| <mx:Object label="OR" data="Salem"/> |
| <mx:Object label="FL" data="Tallahassee"/> |
| <mx:Object label="MN" data="Saint Paul"/> |
| <mx:Object label="NY" data="Albany"/> |
| </mx:Array> |
| </mx:ArrayCollection> |
| |
| <!-- Buttons to filter, sort, or reset the view in the second ComboBox |
| control. --> |
| <mx:HBox width="100%"> |
| <mx:Button id="sortButton" label="Sort" click="sortAC();"/> |
| <mx:Button id="filterButton" label="Filter" click="filterAC();"/> |
| <mx:Button id="resetButton" label="Reset" click="resetAC();"/> |
| </mx:HBox> |
| <mx:VBox width="550" borderStyle="solid" paddingTop="10" paddingLeft="10"> |
| <mx:Label text="This box retains original order and contents of the Array:"/> |
| <!-- A ComboBox populated by the underlying Array object. |
| This control shows that Array retains its original order. --> |
| <mx:ComboBox id="cb2" rowCount="10" dataProvider="{myArray}"/> |
| <mx:HRule/> |
| <mx:Label text="This box reflects the changes to the Wrapper:"/> |
| |
| <mx:ComboBox id="cb1" rowCount="10" dataProvider="{wrapper}"/> |
| <mx:HRule/> |
| <mx:Label text="This box reflects the changes to the ArrayCollection:"/> |
| |
| <mx:ComboBox rowCount="10" dataProvider="{myAC}"/> |
| </mx:VBox> |
| </mx:Application> |
В результате получаем фильтрацию исключительно на уровне view. А модель живет своей счастливой и долгой жизнью. =)
Этот же подход можно использовать и при необходимости показывать одну и ту же коллекцию в разных контролах с разными фильтрами.