Apache flex 将行添加到Flex DataGrid而不更改dataProvider

Apache flex 将行添加到Flex DataGrid而不更改dataProvider,apache-flex,datagrid,Apache Flex,Datagrid,我正在创建标准的单击添加行控件,但我真的不想用占位符弄脏数据提供程序,因为它绑定到模型,可能最终会出现在数据库中。是否有方法添加数据提供程序中未表示的行?我开始直接向listItems添加一个项目,但之后需要在rowInfo中添加一个项目,然后需要在rowMap中添加一个引用 有什么好主意吗?好的,它不好看也不整洁,但很管用 利用SOTC的一些示例: 基本上,我使用两个集合。我扩展了DataGrid并为sourceDataProvider添加了另一个属性。在这个setter中,我为dataPr

我正在创建标准的单击添加行控件,但我真的不想用占位符弄脏数据提供程序,因为它绑定到模型,可能最终会出现在数据库中。是否有方法添加数据提供程序中未表示的行?我开始直接向listItems添加一个项目,但之后需要在rowInfo中添加一个项目,然后需要在rowMap中添加一个引用


有什么好主意吗?

好的,它不好看也不整洁,但很管用

利用SOTC的一些示例:

基本上,我使用两个集合。我扩展了DataGrid并为sourceDataProvider添加了另一个属性。在这个setter中,我为dataProvider创建了一个新的ArrayCollection,这样它们就不再链接。我还调用添加占位符对象,以便单击此处添加到数据提供程序

[Bindable]
        public function get sourceDataProvider():ArrayCollection
        {
            return _sourceDataProvider;
        }

        public function set sourceDataProvider(value:ArrayCollection):void
        {
            _sourceDataProvider= value;
             dataProvider = new ArrayCollection(value.source.concat());
             addPlaceholderItem();
        }
当itemEditor准备提交值时,我只需手动更新_sourceDataProvider。不要试图使用setter,将其添加到私有副本中。此时,占位符项已被编辑,因此我们需要再次调用该方法来创建虚拟对象

public function editEnd(e:DataGridEvent):void
        {
            // Adding a new task
            if(e.itemRenderer.data.condition != DUMMY_PLACEHOLDER_DATA && e.rowIndex == dataProvider.length - 1)
            {
                _sourceDataProvider.addItem(e.itemRenderer.data);
                destroyItemEditor();
                callLater(addPlaceholderItem);
                e.preventDefault();
            }
            dataProvider.refresh();
        }
请记住,我正在控制在itemEditor中调用editEnd的时间。我有一个按钮点击运行commitValues方法

private function commitValues():void
        {
            //change the "data" here


            //force datagrid to endEdit
            var grid:DataGrid = listData.owner as DataGrid;
            if(grid)
            {
                grid.editedItemPosition = null;
                grid.selectedIndex = -1;
            }
        }

好吧,它不好看也不整洁,但它很管用

利用SOTC的一些示例:

基本上,我使用两个集合。我扩展了DataGrid并为sourceDataProvider添加了另一个属性。在这个setter中,我为dataProvider创建了一个新的ArrayCollection,这样它们就不再链接。我还调用添加占位符对象,以便单击此处添加到数据提供程序

[Bindable]
        public function get sourceDataProvider():ArrayCollection
        {
            return _sourceDataProvider;
        }

        public function set sourceDataProvider(value:ArrayCollection):void
        {
            _sourceDataProvider= value;
             dataProvider = new ArrayCollection(value.source.concat());
             addPlaceholderItem();
        }
当itemEditor准备提交值时,我只需手动更新_sourceDataProvider。不要试图使用setter,将其添加到私有副本中。此时,占位符项已被编辑,因此我们需要再次调用该方法来创建虚拟对象

public function editEnd(e:DataGridEvent):void
        {
            // Adding a new task
            if(e.itemRenderer.data.condition != DUMMY_PLACEHOLDER_DATA && e.rowIndex == dataProvider.length - 1)
            {
                _sourceDataProvider.addItem(e.itemRenderer.data);
                destroyItemEditor();
                callLater(addPlaceholderItem);
                e.preventDefault();
            }
            dataProvider.refresh();
        }
请记住,我正在控制在itemEditor中调用editEnd的时间。我有一个按钮点击运行commitValues方法

private function commitValues():void
        {
            //change the "data" here


            //force datagrid to endEdit
            var grid:DataGrid = listData.owner as DataGrid;
            if(grid)
            {
                grid.editedItemPosition = null;
                grid.selectedIndex = -1;
            }
        }

答案是编写自己的IList实现,并将其用作默认列表的数据提供程序

像下面这样的东西应该有用

public class NewItemIList implements IList {

    public var sourceCollection : ICollectionView;
    public var additionalCollection : ICollectionView;
    public var additionalPositioning : String = "end";

    public override function get length() : int {
        return sourceCollection.length + additionalCollection.length;
    }

    public override function getItemAt( index : int = 0, prefetch : int = 0) : Object {
        if ( additionalPositioning  == "end" ) {
            if ( index > sourceCollection.length ) {
                return additionalCollection.getItemAt(index - sourceCollection.length );
            } else {
                return sourceCollection.getItemAt(index);
            }
        } else {
            do same for other positions...
        }
    }

答案是编写自己的IList实现,并将其用作默认列表的数据提供程序

像下面这样的东西应该有用

public class NewItemIList implements IList {

    public var sourceCollection : ICollectionView;
    public var additionalCollection : ICollectionView;
    public var additionalPositioning : String = "end";

    public override function get length() : int {
        return sourceCollection.length + additionalCollection.length;
    }

    public override function getItemAt( index : int = 0, prefetch : int = 0) : Object {
        if ( additionalPositioning  == "end" ) {
            if ( index > sourceCollection.length ) {
                return additionalCollection.getItemAt(index - sourceCollection.length );
            } else {
                return sourceCollection.getItemAt(index);
            }
        } else {
            do same for other positions...
        }
    }

没有扩展DataGrid就不行


我怀疑向数据提供程序添加一行也不能解决问题。DataGrid使用渲染器循环,这意味着它只为屏幕上的项目创建行。我假设如果您希望始终显示新的项目行。由于渲染器回收,用户将始终必须滚动到列表底部才能找到“newitem”行

必须扩展数据网格


我怀疑向数据提供程序添加一行也不能解决问题。DataGrid使用渲染器循环,这意味着它只为屏幕上的项目创建行。我假设如果您希望始终显示新的项目行。由于渲染器回收,用户将始终必须滚动到列表底部才能找到“newitem”行

一个好问题+1。这是一个非常实用的用例,我已经考虑过很多次了。希望有人有一个好的答案…一个好问题+1。这是一个非常实用的用例,我已经考虑过很多次了。希望有人能给出一个好的答案……如果您实现ICollectionView而不是IList,它可能会工作得更好。ListBase将ILists包装在ListCollectionView中,在该视图中使用ICollectionView时未加修饰。如果我将另一个控件绑定到网格的数据提供程序,它将永远不会显示人造行?听起来我需要更多地了解IList是如何使用的……在我的示例中,您不会将控件绑定到网格的DP,而是绑定到sourceCollection。这样,两个控件共享同一个源,但网格中添加了一行或多行。。。它具有相当的可扩展性。如果实现ICollectionView而不是IList,它可能会工作得更好。ListBase将ILists包装在ListCollectionView中,在该视图中使用ICollectionView时未加修饰。如果我将另一个控件绑定到网格的数据提供程序,它将永远不会显示人造行?听起来我需要更多地了解IList是如何使用的……在我的示例中,您不会将控件绑定到网格的DP,而是绑定到sourceCollection。这样,两个控件共享同一个源,但网格中添加了一行或多行。。。它是相当可扩展的