-1

我搜索了一个使用页脚创建 DataGrid 的解决方案,我发现一些想法可以使用高级 DataGrid 来做到这一点,但它看起来非常困难。

那么您知道 DataGrid 上的页脚的简单解决方案吗?

非常感谢

4

1 回答 1

1

我昨天在我自己的 dataGrid 页脚问题中遇到了这个问题。从那以后我设法解决了它,并且由于没有答案(我知道这是一个老问题),并且有人可能仍然需要解决方案,所以我会在这里发布。

最终结果应该是这样的:http: //prntscr.com/5cka32

开始吧:

首先要提供页脚支持,我们需要创建一个扩展 UIComponent 的DataGridFooterBase类。添加两个属于 mx_internal 命名空间的属性(visibleColumns:Array 和 footerItemsChanged:Boolean)(我决定只有系统需要能够看到它们)。

public class DataGridFooterBase extends UIComponent
{
    mx_internal var visibleColumns:Array;
    mx_internal var footerItemsChanged:Boolean;

    public function DataGridFooterBase()
    {
        super();
    }
}

接下来,我们将创建实际的DataGridFooter类,它将扩展DataGridFooterBase类。基本上,此类将接收一个ICollection dataProvider,其中的对象将显示在页脚中。想象一下这种情况,您有一个网格,其中存在有关发票的信息。您需要在金额*价格列下方显示所有发票的总和。但是,发票可以有不同的货币(欧元和美元),您需要按货币显示总和。这就是为什么我们有一个ICollection类型的 dataProvider,它将表示行和列。

public class DataGridFooter extends DataGridFooterBase
{
    protected var dataGrid:Grid;
    protected var footerItems:Array=[];
    protected var cachedFooterHeight:Number=0;
    protected var cachedPaddingBottom:Number=0;
    protected var cachedPaddingTop:Number=0;

    private var _dataProvider:Object;

    public var leftOffset:Number=0;
    public var topOffset:Number=0;
    public var rightOffset:Number=0;
    public var bottomOffset:Number=0;

    public function DataGridFooter()
    {
        super();
    }

    public function set dataProvider(value:Object):void
    {
        if (value != null && !(value is ArrayCollection))
            value=new ArrayCollection([value]);
        _dataProvider=value;
        footerItemsChanged=true;
    }

    public function get dataProvider():Object
    {
        return _dataProvider;
    }

    override protected function createChildren():void
    {
        dataGrid=parent as Grid;
    }
}

这是一个基本设置。接下来我们需要实现measure()updateDisplayList()方法。他们将确保一切都干净整洁。所以让我们重写这两种方法:

override protected function measure():void
{
    super.measure();
    cachedFooterHeight=dataGrid._explicitFooterHeight ? dataGrid.footerHeight : 22;
    cachedPaddingBottom=getStyle("paddingBottom");
    cachedPaddingTop=getStyle("paddingTop");
    measuredHeight=cachedFooterHeight;
}

override protected function updateDisplayList(w:Number, h:Number):void
{
    graphics.clear();
    graphics.beginFill(0xCFCFCF);
    graphics.drawRect(0, 0, unscaledWidth, unscaledHeight);
    graphics.endFill();
    graphics.lineStyle(1, 0x696969);
    graphics.moveTo(0, 0);
    graphics.lineTo(unscaledWidth, 0);
    graphics.endFill();
    updateFooterItemsLayout();
}

如果您想知道graphics是什么,我用它来为 Footer 着色,使其与 dataGrid 行不同。之后,我们需要重写commitProperties()方法,在该方法中我们检查 dataProvider 是否已更改。如果是,我们需要在更新显示列表之前重新绘制所有的页脚元素(否则会出现性能问题)

override protected function commitProperties():void
{
    super.commitProperties();
    if (footerItemsChanged)
    {
        footerItemsChanged=false;
        clearListItems();
        var cols:Array=visibleColumns;
        if ((cols && cols.length > 0 || dataGrid.footerVisible))
        {
            if (_dataProvider != null)
            {
                for (var j:int=0; j < _dataProvider.length; j++)
                {
                    addListItems(j, dataProvider.getItemAt(j));
                }
            }
            else
            {
                addListItems(0, null);
            }
        }
    }
}

让我们继续,到目前为止一切都是准备工作,现在我们需要将IListItemRenderer对象添加和删除到我们的新Footer的实际方法。所以让我们创建 2 个方法,addListItems()removeListItems()

private function addListItems(row:int=0, data:Object=null):void
{
    if (footerItems == null)
        return;
    var cols:Array=visibleColumns;
    footerItems[row]=[];
    var rowData:DataGridListData;
    var item:IListItemRenderer;
    var colNum:int=0;
    var column:GridColumn;
    while (cols && colNum < cols.length)
    {
        column=cols[colNum];
        item=ObjectUtil.copy(column.cachedFooterRenderer) as IListItemRenderer;
        if (item == null)
        {
            item=new DataGridItemRenderer();
            item.styleName=column;
            column.cachedFooterRenderer=item;
        }
        var label:String="";
        if (data != null)
        {
            if (column.labelFunction == null)
                label=String(AbcUtils.findValueInObject(data, column.dataField.split(".")));
            else
                label=String(column.labelFunction(data, column));
            if (label == null || label == "null" || label == "NaN")
                label="";
        }
        rowData=new DataGridListData(label, column.dataField, colNum, uid, dataGrid, 0);
        if (item is IDropInListItemRenderer)
            IDropInListItemRenderer(item).listData=rowData;
        item.data=column;
        item.visible=true;
        addChild(DisplayObject(item));
        footerItems[row][colNum]=item;
        colNum++;
    }
}

private function clearListItems():void
{
    if (footerItems == null)
        return;
    for (var rows:int=0; rows < footerItems.length; rows++)
    {
        var cols:Array=footerItems[rows];
        for (var i:int=0; i < cols.length; i++)
        {
            removeChild(DisplayObject(cols[i]));
        }
    }
    footerItems.splice(0, footerItems.length);
}

这两种方法的基本作用是,它们获取所有可见列并为 dataProvider 集合(footerItems[row][column])中的每个项目创建一个DataGridItemRenderer,并将它们添加到我们的 Footer 类的显示列表中,或者删除它们。我们在此类中需要的最后一个方法将确保所有项目都根据它们“所属”的列正确定位。

private function updateFooterItemsLayout():void
{
    if (_dataProvider == null || footerItems == null || footerItems.length == 0)
        return;
    for (var row:int=0; row < _dataProvider.length; row++)
    {
        var cols:Array=visibleColumns;
        var item:IListItemRenderer;
        var colNum:int=0;
        var ww:Number=0;
        var xx:Number=0;
        var column:GridColumn;
        while (cols && colNum < cols.length)
        {
            column=cols[colNum];
            item=footerItems[row][colNum];
            item.explicitWidth=ww=column.width;
            UIComponentGlobals.layoutManager.validateClient(item, true);
            item.setActualSize(ww, item.getExplicitOrMeasuredHeight());
            if (row == 0)
                item.move(xx, cachedPaddingTop);
            else
                item.move(xx, item.height * row + cachedPaddingTop);
            xx+=ww;
            colNum++;
        }
    }
}

基本上就是这样。现在我们需要调整我们的 DataGrid 和 DataGridColumn 类来连接我们的新 Footer 类。


所以让我们继续DataGrid类。我们需要创建一个新的 Grid 类来扩展 DataGrid 类。

public class Grid extends DataGrid
{
    public function Grid()
    {
        super();
    }

    //==== footer specific stuff =======
    protected var footer:DataGridFooterBase;
    mx_internal var footerClass:Class=DataGridFooter;
    private var _enableFooter:Boolean;
    private var _footerHeight:int=22;
    mx_internal var _explicitFooterHeight:Boolean;

    mx_internal function get dataGridFooter():DataGridFooterBase
    {
        return footer;
    }

    [Bindable("enableFootersChanged")]
    [Inspectable(category="General", defaultValue="false")]
    public function get enableFooters():Boolean
    {
        return _enableFooter;
    }

    public function set enableFooters(value:Boolean):void
    {
        if (value == _enableFooter)
            return;
        _enableFooter=enabled;
        invalidateDisplayList();
        dispatchEvent(new Event("enableFootersChanged"));
    }

    mx_internal function get footerVisible():Boolean
    {
        return enableFooters && (footerHeight > 0) && footer != null;
    }

    [Bindable("resize")]
    [Inspectable(category="General", defaultValue="22")]
    public function get footerHeight():Number
    {
        return _footerHeight;
    }

    public function set footerHeight(value:Number):void
    {
        _footerHeight=value;
        _explicitFooterHeight=true;
        invalidateDisplayList();
    }

    public function setFooterValues(value:Object):void
    {
        if (footer != null)
            DataGridFooter(footer).dataProvider=value;
    }
    //==========================================

    override protected function createChildren():void
    {
        super.createChildren();
        if (enableFooters && footer == null)
        {
            footer=new footerClass();
            addChild(footer);
        }
    }

    override public function invalidateDisplayList():void
    {
        super.invalidateDisplayList();
        if (footer != null)
        {
            footer.invalidateSize();
            footer.invalidateDisplayList();
        }
    }

    override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
    {
        super.updateDisplayList(unscaledWidth, unscaledHeight);
        if (footer != null)
        {
            footer.visibleColumns=visibleColumns;
            footer.invalidateSize();
            footer.validateNow();
        }
        if (footerVisible && verticalScrollBar && verticalScrollBar.visible)
        {
            var maxHeight:Number=this.verticalScrollBar.height - this.footer.height;
            verticalScrollBar.setActualSize(verticalScrollBar.width, maxHeight);
        }
    }

    override protected function adjustListContent(unscaledWidth:Number=-1, unscaledHeight:Number=-1):void
    {
        super.adjustListContent(unscaledWidth, unscaledHeight);
        var refY:Number=header.height;
        var additionalReservedHeight:Number=0;
        additionalReservedHeight+=footerVisible ? footerHeight : 0;
        listContent.setActualSize(listContent.width, listContent.height - additionalReservedHeight);
        refY+=listContent.height;
        if (footerVisible)
        {
            footer.move(listContent.x, refY);
            footer.setActualSize(listContent.width, footerHeight);
            refY+=footer.height;
        }
    }

    override protected function measure():void
    {
        super.measure();
        var additionalReservedHeight:Number=0;
        if (enableFooters)
            additionalReservedHeight+=footerHeight;
        this.measuredHeight=header.getExplicitOrMeasuredHeight() + additionalReservedHeight + (rowHeight * rowCount) + viewMetrics.bottom + viewMetrics.top;
        this.measuredMinHeight=header.getExplicitOrMeasuredHeight() + additionalReservedHeight + (rowHeight * rowCount) + viewMetrics.bottom + viewMetrics.top;
    }
}

我相信这门课或多或少是不言自明的。要将值设置为页脚,您需要使用setFooterValues()函数,您可以使用单个对象或对象的ICollection。您需要做的另一件事是,如果您希望页脚中有多行,则需要显式设置footerHeight属性(或修改Footer 类中的measure()方法以根据集合中的项目数自动缩放)。

我们需要做的最后一件事是修改DataGridColumn类,为IListItemRenderer添加一个存储。这里是:

public class GridColumn extends DataGridColumn
{
    mx_internal var cachedFooterRenderer:IListItemRenderer;

    public function GridColumn(columnName:String=null)
    {
        super(columnName);
    }
}

就是这样。希望这对某人有所帮助,并且不是 TL;DR;:) 干杯。

于 2014-12-02T20:45:43.243 回答