Flex: Database driven DataGrid: arrows disappearing - apache-flex

In Flex I'm using the following code to allow sorting in a DataGrid (the data is paged and sorted serverside).
private function headerReleaseHandler(event:DataGridEvent):void
{
var column:DataGridColumn = DataGridColumn(event.currentTarget.columns[event.columnIndex]);
if(this.count>0)
{
if(this.query.SortField == column.dataField)
{
this.query.SortAscending = !this.query.SortAscending;
}
else
{
this.query.SortField = column.dataField;
this.query.SortAscending = true;
}
this.fill();
}
event.preventDefault();
}
This works perfectly, except that the arrows that indicate sorting isn't shown. How can I accomplish that?
Thanks!
/Niels

There is an example here if this is what you are looking for:
http://blog.flexexamples.com/2008/02/28/displaying-the-sort-arrow-in-a-flex-datagrid-control-without-having-to-click-a-column/
It looks like you need to refresh the collection used by your dataprovider.

I have encountered the same problem and the only solution I found was to override the DataGrid and create a custom one.
Here is the class:
public class DataGridCustomSort extends DataGrid
{
public function DataGridCustomSort()
{
super();
addEventListener(DataGridEvent.HEADER_RELEASE,
headerReleaseHandlerCustomSort,
false, EventPriority.DEFAULT_HANDLER);
}
public function headerReleaseHandlerCustomSort(event:DataGridEvent):void {
mx_internal::sortIndex = event.columnIndex;
if (mx_internal::sortDirection == null || mx_internal::sortDirection == "DESC")
mx_internal::sortDirection = "ASC";
else
mx_internal::sortDirection = "DESC";
placeSortArrow();
}
}
You have to specifically call the placeSortArrow() method when you get the HEADER_RELEASE event and set the column index and direction information.

in the above code what does "this" refer to is it the datagrid because I am confused by this.query.SortField , I am assuming 'this' and "query' are your own custom objects. and why are you checking for count. what count is that.
Regards
-Mohan

Related

Binding to a Property that only have get method

I have a question regarding binding in WinRT.
I have a Viewmodel like this:
public class MainPageViewModel : INotifyPropertyChanged
{
private ObservableCollection<Vehicle> _vehicles = new ObservableCollection<Vehicle>();
public ObservableCollection<Vehicle> Vehicles
{
get { return _vehicles; }
set { _vehicles = value; }
}
and also I have some properties that I get the value from this main list, for example
public int GetType1Vehicles
{
get { return Vehicles.Where(x => x.Type == Type1).Count(); }
}
public int TotalVehicles
{
get { return Vehicles.Count(); }
}
I binded a UI textbox to a "GetType1Vehicles" and another textbot to a "TotalVehicles". The problem is that when I update the Vehicle List, the ListView with all vehicles is correctly updated but the Total and the Type don't. What I doing wrong?
Anybody can help me? Thanks!
UPDATE
I found a workarround, but I'm not sure that is the best approach. Every time that I change some from the list, call manually the methods:
RaisePropertyChanged("GetType1Vehicles");
RaisePropertyChanged("TotalVehicles");
Is the correct approach?
You are correct in that you will need to manually call RaisePropertyChanged. Anyway, why do you have a TotalVehicles property when you could just bind to "Vehicles.Count"?
David is right, why this TotalVehicles property ?
With an ObservableCollection, you should not call the Count() method, just use the Count property.
The Count method is usefull if you want to count only the items with a specific value, not the size of the collection, that's the job of the property.

How to data bind Entity Framework objects to a FormView

I am data binding to many FormView controls using EF entity instances, but I have to resort to this ridiculous kludge in order to achieve what I want without using EntityDataSource controls:
propertyHeaderSection.DataSource = new List<PropertyDetailsModel> { _propertyDetails };
I suspect I will have to derive my own control from FormView and enable it to accept an almost POCO as a data source. Where do I start?
This is my implementation, sort of the same idea as patmortech, but i also found out that the ValidateDataSource method on the BaseDataBoundControl is what throws the exception at run-time if your datasource isn't enumerable.
public class CustomFormView : System.Web.UI.WebControls.FormView
{
public override object DataSource
{
get
{
if (!(base.DataSource is IEnumerable))
return new[] {base.DataSource};
return base.DataSource;
}
set
{
base.DataSource = value;
}
}
// This method complains at run time, if the datasource is not
// IListSource, IDataSource or IEnumerbale
protected override void ValidateDataSource(object dataSource)
{
//base.ValidateDataSource(dataSource);
}
}
EDIT:
Considering the suggestion, i've made some changes to the way i check if the assigned DataSource is enumerable or not. I have also managed to create a sample app (VS 2010 Solution) to demo the changes. The app can be downloaded from http://raghurana.com/blog/wp-content/attachments/FormViewDataProblem.zip
In short this is what i am checking to ensure that the existing datasource can be enumerated already or not:
public static bool CanEnumerate( this object obj )
{
if (obj == null) return false;
Type t = obj.GetType();
return t.IsArray ||
t.Implements(typeof (IEnumerable).FullName) ||
t.Implements(typeof (IListSource).FullName) ||
t.Implements(typeof (IDataSource).FullName);
}
Please feel free to suggest more changes, if this isnt quite the desired functionality. Cheers.
Not sure it's the best idea in the world, but this is how you could derive from FormView to allow single object data source values. It basically does the same check that the ValidateDataSource does internally, and then creates a list wrapper for the item if it's not already a valid type.
public class SingleObjectFormView : System.Web.UI.WebControls.FormView
{
public override object DataSource
{
get
{
return base.DataSource;
}
set
{
//will check if it's an expected list type, and if not,
//will put it into a list
if (! (value == null || value is System.Collections.IEnumerable || value is System.ComponentModel.IListSource || value is System.Web.UI.IDataSource) )
{
value = new List<object> { value };
}
base.DataSource = value;
}
}
}

Flex combo box labelfunction

I have two questions regarding the Flex combo box.
The string representing the function name will be read from xml # run time.
var combo:ComboBox = new ComboBox();
combo.labelFunction = "functionName";
How can I achieve this?
So the first name, which is to be displayed in the combo box, can be only retrieved by accessing another DTO, called person and then its first name.
var combo:ComboBox = new ComboBox();
combo.labelField= "person.firstName";
My class looks like this,
public class Test
{
public var person:PersonDTO;
}
public class PersonDTO
{
public var firstName:String;
}
Is it possible to access any multi-level text using the combo box label field ?
You need to pass the function not the name.
Doing this
combo.labelFunction = "functionName";
Is passing a string.
The only work around I can think of is to make a switch statement with one case for each function you may have. Then call that with "case" from within your xml.
switch( xml.#labelfunction ){
case 'func1':
combo.labelFunction = this.func1;
break;
case 'func2':
combo.labelFunction = this.func2;
break;
}
Its hacky but should work.
ad 1) labelFunction
Calling functions when you know only the name as String is quite easy. The following snippets shows how you can execute a function that is a member of the same class. In case you need to call a function from another class replace this with the according variable name.
private function comboBox_labelFunction(item:Object):String
{
var functionName:String = myXml.#labelFunctionName;
return this[functionName](item);
}
ad 2) labelField
It's normally not possible to use "person.firstName" as labelField. However, you should be able use it within your labelFunction. Something like this should work...
private function comboBox_labelFunction(item:Object):String
{
var labelField:String = "person.firstName";
var attributeNames:Array = labelField.split(".");
for each (var attributeName:String in attributeNames)
{
if (item && item.hasOwnProperty(attributeName))
item = item[attributeName];
else
return null;
}
return item;
}

TextInput as ItemRenderer in DataGrid :Scroll Issue

I use textInput as ItemRenderer for all columns of a datagrid.I need to set editability of first row as false.I did it on creationComplete of the itemRenderer.Also tried overriding upDateDislayList.
It works fine for the first row.But some other rows also get their editability changed to false.Also on scroll many rows get their editability changed.Please help.
override public function set data(value:Object):void
{
super.data = value;
if(listData.owner.name == "headCountGrid")
{
if(data != null && qbpHttpServ.rowDataHcGridArr != null)
{
if(data["column1Data"] == qbpHttpServ.rowDataHcGridArr[0]["column1Data"])
{
this.editable = false;
}
}
}
}
override protected function updateDisplayList(unscaledWidth:Number,unscaledHeight:Number):void{
super.updateDisplayList(unscaledWidth,unscaledHeight);
var g:Graphics = graphics;
g.clear();
}
Do you know that items in lists are reused? Make sure they are controlled entirely by set data() function. Pass editability flag with data.

flex select value from Combo

My goal is to create a generic function that selects a value in a combobox accoring to a value.
(My comoBox holds arrayCollection as dataProvider.)
The difficulty is infact to get a propertyname in runtime mode
public function selectComboByLabel(combo:ComboBox , propetryName:String, value:String):void {
var dp:ArrayCollection = combo.dataProvider as ArrayCollection;
for (var i:int=0;i<dp.length;i++) {
if (dp.getItemAt(i).propertyName==value) {
combo.selectedIndex = i;
return;
}
}
}
the line if (dp.getItemAt(i).propertyName==value)
is of course incorrect.
It should be arther something like: dp.getItemAt(i).getPropertyByName(propertyName)
Any clue on how to that ?
Don't use Object Property notation. Do this:
dp.getItemAt(i)[propertyName]
In addition to what Flextras said, you could also redo your for loop to make it easier to read:
for each(var item:Object in dp) {
if(item[propertyName] == value) {
combo.selectedItem = item;
return;
}
}

Resources