我有一個自定義的FilterColumnHeaderRenderer帶有一個HBox,在一個標題的列標題,一個Textinput爲過濾器文本和Label來清除過濾器。現在我希望只在點擊標題時進行列分類。Datagrid排序只在單擊headerRenderer中的特定部分
目前我使用HeaderRelease上的sortCompareFunction作爲整個columnHeader。
你會如何解決這個需求?
完整的代碼,SearchableDataGrid:
package components{
import flash.events.TextEvent;
import mx.collections.ArrayCollection;
import mx.controls.Alert;
import mx.controls.DataGrid;
import mx.controls.dataGridClasses.DataGridColumn;
import mx.core.ClassFactory;
import mx.events.DataGridEvent;
import mx.formatters.DateFormatter;
import mx.utils.ObjectUtil;
[Event(name="itemsFiltered", type="components.SearchableDataGridFilterEvent")]
public class SearchableDataGrid extends DataGrid{
private var _searchableDataProvider:ArrayCollection;
private var _filterStrings:Object = new Object();
private var _dataTypes:Object = new Object();
private var _fieldFocus:String = "";
private var _totalItems:int = 0;
private var _dataFormatter:DateFormatter = null;
public var _reloadQuery:Boolean = false;
public function SearchableDataGrid(){
super();
init();
}
private function init():void{
//initialise a standart DateFormatter
var ft:DateFormatter = new DateFormatter();
ft.formatString = "YYYY-MM-DD";
this.dateFormatter = ft;
}
private function numericSortByField(fieldName:String):Function {
return function(obj1:Object, obj2:Object):int {
var testFlag1:Boolean = isNaN(Number(obj1[fieldName]));
var testFlag2:Boolean = isNaN(Number(obj2[fieldName]));
// if one value is not a number => string compare
if (testFlag1 || testFlag2){
var value1:String = (obj1[fieldName] == '' || obj1[fieldName] == null) ? null : new String(obj1[fieldName]);
var value2:String = (obj2[fieldName] == '' || obj2[fieldName]== null) ? null : new String(obj2[fieldName]);
return ObjectUtil.stringCompare(value1, value2, true);
}else{
var value1Number:Number = (obj1[fieldName] == '' || obj1[fieldName] == null) ? null : new Number(obj1[fieldName]);
var value2Number:Number = (obj2[fieldName] == '' || obj2[fieldName] == null) ? null : new Number(obj2[fieldName]);
return ObjectUtil.numericCompare(value1Number, value2Number);
}
}
}
private function setHeaderRenderer():void{
var hr:FilterHeaderRendererFactory = new FilterHeaderRendererFactory(this);
for(var i:int = 0; i < super.columns.length; i++){
super.columns[i].showDataTips = true;
super.columns[i].headerRenderer = hr;
super.columns[i].itemRenderer = new ClassFactory(components.SearchableDGItemRenderer);;
super.columns[i].sortCompareFunction = this.numericSortByField(super.columns[i].dataField);
}
}
private function dataBindingChanged():void{
if (_reloadQuery == false){
_filterStrings = new Object();
}else{
Alert.show("You are reloading the same query, your filter strings are reapplied", "Information");
}
_dataTypes = new Object();
_fieldFocus = "";
setHeaderRenderer();
prepareDataFilter();
}
public function set searchableDataProvider(val:ArrayCollection):void{
this._searchableDataProvider = val;
_totalItems = val.length;
this.dataProvider = this._searchableDataProvider;
dataBindingChanged();
}
private function prepareDataFilter():void{
this._searchableDataProvider.filterFunction = dataFilter;
this._searchableDataProvider.refresh();
var ev:SearchableDataGridFilterEvent = new SearchableDataGridFilterEvent(this._searchableDataProvider.length, this._totalItems, this.filterStrings);
this.dispatchEvent(ev);
}
private function dataFilter(item:Object):Boolean{
var isMatch:Boolean = true;
for (var field:String in _filterStrings){
var sP:String = _filterStrings[field]; //searchpattern
if(sP == null){
continue;
}
if(item[field] == null){
isMatch = false;
return isMatch;
}
var pattern:RegExp = new RegExp("^" + sP.toLowerCase().replace(new RegExp(/%/g), ".*"));
if(item[field] is Date){
//special check for date columns
if(!pattern.test(this.dateFormatter.format(item[field] as Date)))
{
isMatch = false;
return isMatch;
}
}else{
//its not a date column
if(!pattern.test((item[field].toString()).toLowerCase()))
{
isMatch = false;
return isMatch;
}
}
}
return isMatch;
}
public function get filterStrings():Object{
return this._filterStrings;
}
public function setFilterString(fieldName:String, value:String):void{
this._filterStrings[fieldName] = value;
if(value == ""){
delete this._filterStrings[fieldName];
}
_fieldFocus = fieldName;
prepareDataFilter();
}
public function getFilterString(fieldName:String):String{
if(this._filterStrings[fieldName] == null){
return "";
}
return this._filterStrings[fieldName];
}
public function setDataType(fieldName:String, value:String):void{
this._dataTypes[fieldName] = value;
}
public function getDataType(fieldName:String):String{
if(this._filterStrings[fieldName] == null){
return "";
}
return this._filterStrings[fieldName];
}
public function getFieldFocus():String{
return this._fieldFocus;
}
public function set dateFormatter(val:DateFormatter):void{
this._dataFormatter = val;
}
public function get dateFormatter():DateFormatter{
return this._dataFormatter;
}
}
}
完整的代碼,FilterColumnHeaderRenderer:
package components{
import flash.events.FocusEvent;
import flash.events.KeyboardEvent;
import flash.events.MouseEvent;
import flash.events.TextEvent;
import flash.text.TextField;
import flash.ui.Keyboard;
import mx.containers.HBox;
import mx.containers.Tile;
import mx.containers.VBox;
import mx.controls.Button;
import mx.controls.Label;
import mx.controls.LinkButton;
import mx.controls.TextInput;
import mx.controls.dataGridClasses.DataGridColumn;
import mx.events.DataGridEvent;
import mx.events.FlexEvent;
public class FilterColumnHeaderRenderer extends VBox{
private var title:Label;
private var filter:TextInput;
private var clearFilter:Label;
private var filterHBox:HBox;
private var tfHasFocus:Boolean = false;
private var dataFieldName:String;
private var dataObj:DataGridColumn;
private var _dataGrid:SearchableDataGrid;
public function FilterColumnHeaderRenderer(){
super();
this.verticalScrollPolicy = "off";
this.horizontalScrollPolicy = "off";
this.addEventListener(FlexEvent.CREATION_COMPLETE, creationComplete);
title = new Label();
filter = new TextInput();
clearFilter = new Label();
filterHBox = new HBox();
title.percentWidth = 100;
filterHBox.percentWidth = 100;
clearFilter.width = 10;
clearFilter.toolTip = "Clear the filter for this column"
clearFilter.htmlText = "x";
this.addChildAt(title, 0);
filterHBox.addChildAt(clearFilter, 0);
filterHBox.addChildAt(filter, 1);
this.addChildAt(filterHBox, 1);
clearFilter.addEventListener(MouseEvent.CLICK, resetFilter);
filter.addEventListener(FocusEvent.FOCUS_IN, hasFocus);
filter.addEventListener(FocusEvent.FOCUS_OUT, lostFocus);
filter.addEventListener(TextEvent.TEXT_INPUT, textChange);
filter.addEventListener(KeyboardEvent.KEY_DOWN, textKeyDown);
title.addEventListener(DataGridEvent.HEADER_RELEASE, onHeaderRelease);
}
private function onHeaderRelease(event:DataGridEvent): void {
var rdr:FilterColumnHeaderRenderer = event.itemRenderer as FilterColumnHeaderRenderer;
var dataGrid:SearchableDataGrid = SearchableDataGrid(event.target);
var dataField:String = event.dataField;
var columnIndex:int = event.columnIndex;
}
private function resetFilter(event:MouseEvent):void{
var tmpFieldName:String = event.currentTarget.parent.parent.fieldName;
this._dataGrid.setFilterString(dataFieldName, "");
this.filter.text = "";
}
private function textKeyDown(event:KeyboardEvent):void{
if(this._dataGrid){
if(event.keyCode == flash.ui.Keyboard.BACKSPACE){
var actString:String = this.filter.text;
this._dataGrid.setFilterString(dataFieldName, actString.substr(0, (actString.length > 0 ? actString.length - 1 : 0)));
}
}
}
private function creationComplete(event:FlexEvent):void{
if(this._dataGrid != null && this._dataGrid.getFieldFocus() == dataFieldName){
this.filter.setFocus();
}
}
public function textChange(event:TextEvent):void{
if(this._dataGrid)
{
this._dataGrid.setFilterString(dataFieldName, this._dataGrid.getFilterString(dataFieldName) + event.text);
}
}
private function hasFocus(event:FocusEvent):void{
tfHasFocus = true;
}
private function lostFocus(event:FocusEvent):void{
tfHasFocus = false;
}
override public function set data(value:Object):void{
dataObj = (value as DataGridColumn);
dataFieldName = dataObj.dataField;
this.title.text = dataObj.headerText;
this.title.toolTip = dataObj.headerText;
if(this._dataGrid)
{
var fs:String = this._dataGrid.filterStrings[dataFieldName];
if(fs != null){
this.filter.text = fs;
}
}
this.dispatchEvent(new FilterColumnHeaderRendererCreatedEvent(this, true));
}
public function get hasTextFocus():Boolean{
return this.tfHasFocus;
}
public function get fieldName():String{
return this.dataFieldName;
}
public function setText(newText:String):void{
this.filter.text = newText;
}
public function set dataGrid(value:SearchableDataGrid):void{
this._dataGrid = value;
}
public function get dataGrid():SearchableDataGrid{
return this._dataGrid;
}
}
}
完整的代碼,FilterHeaderRendererFactory:
package components{
import mx.controls.DataGrid;
import mx.core.ClassFactory;
import mx.core.IFactory;
public class FilterHeaderRendererFactory implements IFactory{
private var _base_factory:ClassFactory;
private var _grid:SearchableDataGrid;
public function FilterHeaderRendererFactory(grid:SearchableDataGrid){
_base_factory = new ClassFactory(FilterColumnHeaderRenderer);
_grid = grid;
}
public function newInstance():*{
var o:FilterColumnHeaderRenderer = _base_factory.newInstance() as FilterColumnHeaderRenderer;
o.dataGrid = _grid;
return o;
}
}
}
我明白了。如果我直接對dataProvider進行排序,那麼如何重新實現顯示排序方向的小三角,並且更重要的是重用一個自定義的sortCompareFunction,它可以將數字排序爲數字而不是字符串? – Werner
我不確定三角形的事情。 sortCompareFunction應該是固有的可重用的。試圖這樣做有問題嗎? – JeffryHouser
我能夠重用我的自定義排序功能:sortField.compareFunction = numericSortByField(dataField); 任何關於三角形的事情?讓我谷歌一點;) – Werner