为了保障原创作者在本站发表文章的利益, 并维护本站原创的精神, 特声明: RIAShanghai对有以下任何情况之一的文章将不通知作者并直接进行快意删除:
- 非原创, 或者原创但一文多发;
- 各种形式的广告与吹擂;
- 不符合本站文章格式.
欢迎各位读者监督. 谢谢合作. 另: 作为Adobe正式的UG, 我们将把Adobe不定期分发的软件,书籍及各种纪念品赠送给发文活跃的作者, 共同进步.
You should not assign your model object directly to List/DataGrid/AdvancedDataGrid's dataProvider property. If you do, your model will be changed when the user performs 'read-only' operations, like sorting the view using a column. If at this time, the model is accessed elsewhere, then all the callers will "see" the same sort order as the user - in many cases this is unacceptable. Even worse, bugs caused by unexpected ordering, filtering are usually hard to catch. It's important that you do not assign your model object directly to List/DataGrid/AdvancedDataGrid's dataProvider property. To generalize this rule, a read operation should never result any change in the model.
I'll use a sample application demos the problem described above. This simple application displays employee information on a datagrid. We allow the user to sort the view order in the datagrid. The corresponding code is just below the screenshots.
public var employees:ArrayCollection = new ArrayCollection([
{name: "Jack", gender: "M"},
{name: "Joanne", gender: "F"},
{name: "Jason", gender: "M"}
]);
private function traceInfo():void {
trace(ObjectUtil.toString(employees));
}
The trace output:
| Trace before the 'Name' column header is clicked | after |
(mx.collections::ArrayCollection)#0
filterFunction = (null)
length = 3
list = (mx.collections::ArrayList)#1
length = 3
source = (Array)#2
...
sort = (null)
source = (Array)#2 |
(mx.collections::ArrayCollection)#0
filterFunction = (null)
length = 3
list = (mx.collections::ArrayList)#1
length = 3
source = (Array)#2
...
sort = (mx.collections::Sort)#6
compareFunction = (function)
fields = (Array)#7
[0] (mx.collections::SortField)#8
caseInsensitive = false
compareFunction = (function)
descending = false
name = "name"
numeric = (null)
unique = false
source = (Array)#2 |
Clearly, the model object employees has been changed. ArrayCollection.getItemAt() may return different objects before datagrid sorting and after. The danger of this can never be emphasized enough.
The solution is very simple. You use a ListCollectionView as a controller in MVC:
When no longer used, you need to set the ListCollectionView's list to null to remove event wire with the model object:
(dg.dataProvider as ListCollectionView).list = null;
ListCollectionView, as the name suggests, is a view on an IList. In this case, the employees object is the IList model for the view. Any sorting, filtering happen at the ListCollectionView only. You can use ListCollectionView to add, remove items too. The ListCollectionView delegates write operations to the model IList.
The ArrayCollection class extends ListCollectionView, but this does not mean you should assign the ArrayCollection typed model object to dataProvider directly. Model objects, regardless of their types, must be wrapped through ListCollectionView to pass to Lists/DataGrids.
Whenever you need to show sorted, filtered view on the model object and you do not want to apply the sorting, filtering to the model object, you should used chained ListCollectionView. Do remember to remove the event wiring between ListCollectionView and the model object after use.
There are thousands of hello-world code snippets that demonstrate various kinds of tips. However, when you browse others' examples, beware that they try to solve one problem and yet their code could create many other problems.
One possible exception is that you want the user to edit the order of the elements. In this case, you disable sorting through column headers, set the model object to data grid's dataProvider and implement drag-and-drop to modify the model object directly.
回應
如果我的Model是Array
如果我的Model的属性是Array. 当我要和List/Datagrid进行绑定时,我用ArrayCollection包一下,然后不用了以后,我在用arrayCollection.source把我的Array取回来,是不是你所描述的问题也能相应的解决?
lw0110's Blog: http://chestnutjoelee.spaces.live.com/
是的.
是的. 你可以直接pass这个array给List的dataProvider; List将自动把Array用ArrayCollection包起来.
我用Array做Model
我用Array做Model的话,像这种List/Datagrid把Model改变的情况,就没了吧?
感觉我自己表述问题不清楚...
lw0110's Blog: http://chestnutjoelee.spaces.live.com/
是的, 没了.
是的, 没了. Datagrid只改变ArrayCollection而已.