我有一个带有HBox的自定义FilterColumnHeaderRenderer,在列标题的Label内,过滤器文本的Textinput和用于清除过滤器的Label。现在我希望列排序仅在单击标题时进行。
目前我在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;
}
}
}
答案 0 :(得分:1)
概念上;我这样做:
从自定义标头中调度自定义事件。确保它起泡。在DataGrid上监听该事件,然后直接在sort your dataProvider监听,而不使用内置的DataGrid功能。
答案 1 :(得分:1)
最后我实施了这个解决方案:
请随时询问更准确的信息。这里有相关的源代码:
完整代码,FilterColumnHeaderRenderer:
package components
{
import flash.events.Event;
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:Button;
private var filterHBox:HBox;
private var tfHasFocus:Boolean = false;
private var dataFieldName:String;
private var dataObj:DataGridColumn;
private var _dataGrid:SearchableDataGrid;
[ Embed ( source = "/icons/icon-x.gif" ) ]
public var iconDelete:Class;
public function FilterColumnHeaderRenderer(){
super();
this.verticalScrollPolicy = "off";
this.horizontalScrollPolicy = "off";
this.addEventListener(FlexEvent.CREATION_COMPLETE, creationComplete);
title = new Label();
filter = new TextInput();
clearFilter = new Button();
filterHBox = new HBox();
title.percentWidth = 100;
filterHBox.percentWidth = 100;
filterHBox.setStyle( "horizontalGap", 5 );
clearFilter.toolTip = "Clear the filter for this column"
clearFilter.width = 15;
clearFilter.height = 20;
clearFilter.label = "x";
clearFilter.setStyle ( "fontWeight", "normal" ) ;
clearFilter.setStyle ( "textPadding", 0 ) ;
clearFilter.setStyle ( "paddingLeft", 0 ) ;
clearFilter.setStyle ( "paddingRight", 0 ) ;
clearFilter.setStyle ( "paddingTop", 0 ) ;
clearFilter.setStyle ( "paddingBottom", 0 ) ;
clearFilter.addEventListener(FocusEvent.FOCUS_IN, hasFocus);
clearFilter.addEventListener(FocusEvent.FOCUS_OUT, lostFocus);
filter.addEventListener(FocusEvent.FOCUS_IN, hasFocus);
filter.addEventListener(FocusEvent.FOCUS_OUT, lostFocus);
filter.addEventListener(TextEvent.TEXT_INPUT, textChange);
filter.addEventListener(KeyboardEvent.KEY_DOWN, textKeyDown);
clearFilter.addEventListener(MouseEvent.CLICK, resetFilter);
this.addChildAt(title, 0);
filterHBox.addChildAt(clearFilter, 0);
filterHBox.addChildAt(filter, 1);
this.addChildAt(filterHBox, 1);
}
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;
} }}
searchableDataGrid的相关代码:
package components{
import flash.events.TextEvent;
import mx.collections.*;
import mx.controls.Alert;
import mx.controls.DataGrid;
import mx.controls.advancedDataGridClasses.AdvancedDataGridColumn;
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;
this.addEventListener(DataGridEvent.HEADER_RELEASE, onHeaderRelease);
}
private function onHeaderRelease( event:DataGridEvent ): void {
var dataGrid:SearchableDataGrid = SearchableDataGrid(event.target);
var dataField:String = event.dataField;
var columnIndex:int = event.columnIndex;
var rdr:FilterColumnHeaderRenderer = event.itemRenderer as FilterColumnHeaderRenderer;
if(rdr.hasTextFocus){
event.preventDefault();
}
}
(...)
答案 2 :(得分:0)
由于此处的所有其他评论,我有一个更优雅的解决方案。
我将headerRelease事件侦听器附加到datagrid
<mx:Datagrid headerRelease="onHeaderRelease(event)">
在事件监听器中,我检查了哪个InteractiveObject具有焦点
如果焦点对象不是数据网格,我暂停了事件
protected function onHeaderRelease(e:DataGridEvent):void {
var interactive:InteractiveObject = focusManager.getFocus() as InteractiveObject
var hasFocus:String = flash.utils.getQualifiedClassName(interactive).toString()
if (hasFocus != "mx.controls::DataGrid") { // Can also be AdvancedDataGrid
e.stopImmediatePropagation(); // Use this as needed
e.preventDefault(); // Mandatory
}
}
我希望这有助于下一个发现自己的穷人。